输入二叉树的前序遍历和中序遍历,重建出该二叉树

题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设前序遍历与中序遍历的结果都不含重复的数字。

eg:前序遍历:{1,2,4,7,3,5,6,8};
        中序遍历:{4,7,2,1,5,3,8,6};

二叉树结点定义如下:
struct BinaryTreeNode
{
int _value;
BinaryTreeNode* _left;
BinaryTreeNode* _right;
}

c++实现函数说明:
本题的函数主要是有参构造函数:BinaryTree(int* pre, int* inOrder, int len);
有参构造函数调用函数:BinaryTreeNode* _CreateBinaryTree(BinaryTreeNode*& root,int*& pre, int*& inOrder, int len);
此函数又调用了主要函数:BinaryTreeNode* _RealCreateTree(BinaryTreeNode*& root,int* startPre, int* endPre, int* startIn, int* endIn);

函数void _DestoryBinaryTree(BinaryTreeNode*& root);:递归销毁一棵树;

分析如下:
1.先根据先序遍历创建出根结点:root;
2.再通过中序遍历找出根结点,用根结点的下标计算出左子树的个数;
3.再通过左子树的个数计算出在先序遍历中左子树结尾的位置;
4.通过以上计算,我们已经将二叉树分为左子树和右子树,然后大问题化作小问题;
5.遍历左子树;
6.遍历右子树;


依据上面的思路构建出的二叉树如上图:

代码如下:

#include<iostream>
using namespace std;
struct BinaryTreeNode
{
	int _value;
	BinaryTreeNode* _left;
	BinaryTreeNode* _right;

	BinaryTreeNode(int value = 0)
		:_value(value),_left(NULL), _right(NULL)
	{}
};
class BinaryTree
{
public:
	BinaryTree()
		:root(NULL)
	{}

	BinaryTree(int* pre, int* inOrder, int len)
	{
		_CreateBinaryTree(root, pre, inOrder, len);
	}

	~BinaryTree()
	{
		_DestoryBinaryTree(root);
	}

private:
	void _DestoryBinaryTree(BinaryTreeNode*& root)
	{
		if (root)
		{
			BinaryTreeNode* tmp = root;
			if (tmp->_left)
			{
				_DestoryBinaryTree(tmp->_left);
			}
			if (tmp->_right)
			{
				_DestoryBinaryTree(tmp->_right);
			}
			delete[] tmp;
			tmp = NULL;
		}
	}

	BinaryTreeNode* _CreateBinaryTree(BinaryTreeNode*& root,int*& pre, int*& inOrder, int len)
	{
		if (pre == NULL || inOrder == NULL || len <= 0)
		{
			return NULL;
		}
		return _RealCreateTree(root, pre, pre + len - 1, inOrder, inOrder + len - 1);
	}

	BinaryTreeNode* _RealCreateTree(BinaryTreeNode*& root,int* startPre, int* endPre, int* startIn, int* endIn)
	{
		int rootValue = startPre[0];
		root = new BinaryTreeNode(rootValue);
		
		//1.有一个结点
		if (startPre == endPre)
		{
			if (startIn == endIn && *startPre == *startIn)
			{
				return root;
			}
			else
			{
				cout << "preOrder and InOder is not matching" << endl;
				return NULL;
			}
		}
		
		//2.有多个结点
		int* rootIn = startIn;
		while (rootIn < endIn && *rootIn != root->_value)
		{
			++rootIn;
		}
		if (rootIn == endIn && *rootIn != root->_value)
		{
			cout << "preOrder and InOder is not matching" << endl;
			return NULL;
		}

		//1.通过中序遍历计算左子树的节点个数leftLen
		//2.通过计算出的左子树个数,再计算先序遍历中的左子树中的最后一个节点位置preLeftOfend
		int leftLen = rootIn - startIn;
		int* preLeftOfend = startPre + leftLen;

		//构建左子树
		if (leftLen > 0)
		{
			_RealCreateTree(root->_left, startPre + 1, preLeftOfend, startIn, rootIn - 1);
		}

		//构建右子树
		if (leftLen < endPre - startPre)
		{
			_RealCreateTree(root->_right, preLeftOfend + 1, endPre, rootIn + 1, endIn);

		}
		return root;
	}

private:
	BinaryTreeNode* root;
};

void Test()
{
	int pre[] = { 1, 2, 4, 7, 3, 5, 6, 8 };
	int in[] = { 4, 7, 2, 1, 5, 3, 8, 6 };
	int len = sizeof(pre) / sizeof(pre[0]);
	BinaryTree bt(pre, in, len);
}

void Test2()
{
	int pre[] = { 1, 2, 4, 8, 9, 5, 3, 6, 7 };
	int in[] = { 8, 4, 9, 2, 5, 1, 6, 3, 7 };
	int len = sizeof(pre) / sizeof(pre[0]);
	BinaryTree bt(pre, in, len);
}

void Test3()
{
	int pre[] = { 1, 2, 3, 4, 5, 6 };
	int in[] = { 6, 5, 4, 3, 2, 1 };
	int len = sizeof(pre) / sizeof(pre[0]);
	BinaryTree bt(pre, in, len);
}

void Test4()
{
	int pre[] = { 1, 2, 3, 4, 5, 6 };
	int in[] = { 1, 2, 3, 4, 5, 6 };
	int len = sizeof(pre) / sizeof(pre[0]);
	BinaryTree bt(pre, in, len);
}

void Test5()
{
	int pre[] = { 10 };
	int in[] = { 10 };
	int len = sizeof(pre) / sizeof(pre[0]);
	BinaryTree bt(pre, in, len);
}

void Test6()
{
	int pre[] = { 1,2,3,4,5};
	int in[] = {4,5,7,3,1};
	int len = sizeof(pre) / sizeof(pre[0]);
	BinaryTree bt(pre, in, len);
}

int main()
{
	//1.普通二叉树:Test():不完全二叉树;
	//				Test2():完全二叉树;			
	//2.特殊二叉树:Test3():所有结点没有右结点;
	//				Test4():所有结点没有左节点;
	//				Test5():只有一个结点;
	//3.特殊测试:	Test6():输入的前序与中序不匹配;
	Test();
	Test2();
	Test3();
	Test4();
	Test5();
	Test6();
	return 0;
}


除Test6()外,所有测试都可以通过调试去看构造出的二叉树结构;
Test6()测试不匹配的结果如下图所示:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值