重建二叉树

5 篇文章 0 订阅
2 篇文章 0 订阅

题目:由前序遍历和中序遍历重建二叉树

前序序列:1 2 3 4 5 6 

中序序列:3 2 4 1 6 5

思路:每次以前序遍历序列的第一个数作为根结点,再在中序遍历序列里边找到根结点。根据中序遍历的特点我们可以知道,只有左子树全部访问完之后才会访问根结点,所以我们找到根结点之后,发现根结点之前的数都是根结点的左子树的所有结点,右边的数都是根结点右子树的所有结点。那么,可以以根结点为中心,将中序遍历序列分为两部分,左子树和右子树。

同时将与左子树等长的那部分前序序列作为新的前序序列,右子树也一样。将前序序列和中序序列每次都截成两部分,作为递归入口点进行递归。递归的出口就是找到叶子结点或者说新区间里边只剩下一个值时。

这道题再递归的时候,一定要注意边界条件的更新,如果是数组,要注意下标问题,vector则要弄明白end()的返回值。


#pragma once

template<class T>
struct BinaryTreeNode
{
	T _data;
	BinaryTreeNode<T>* _left;
	BinaryTreeNode<T>* _right;

	BinaryTreeNode(const T& d)
		: _data(d)
		, _left(NULL)
		, _right(NULL)
	{}
};

template<class T>
class ConstructTree
{
public:
	typedef BinaryTreeNode<T> Node;

	ConstructTree(T* preOrder, T* inOrder, size_t length)
	{
		if (preOrder == NULL || inOrder == NULL  || length <= 0)
			_root = NULL;
		else
			_root =  _ConstructTree(preOrder, preOrder + length - 1, 
				inOrder, inOrder + length - 1);
	}

protected:
	Node* _ConstructTree(T* startPre, T* endPre, T* startIn, T* endIn)
	{
		//前序遍历序列的第一个数是根节点的值
		Node* root = new Node(startPre[0]);

		//递归结束条件,找到叶子结点,也就是区间缩小到只剩下一个值
		if (startPre == endPre)
		{
			if (startIn == endIn && *startPre == *startIn)
				return root;
			else
				throw exception("invalid input");
		}

		//在中序遍历中找到根结点
		T* rootIn = startIn;
		while (rootIn <= endIn && *rootIn != root->_data)
		{
			++rootIn;
		}

		//已经遍历完还没右找到根结点
		if (rootIn == endIn && *rootIn != root->_data)
			throw exception("invalid input");

		//已经找到根节点
		size_t leftLengthIn = rootIn - startIn;
		//更新前序遍历的区间范围
		T* newEndPro = startPre + leftLengthIn;

		//构建左子树
		if (leftLengthIn > 0)
		{
			root->_left = _ConstructTree(startPre + 1, newEndPro, startIn, rootIn - 1);
		}

		//构建右子树
		if (leftLengthIn < endPre - startPre)
		{
			root->_right = _ConstructTree(newEndPro + 1, endPre, rootIn + 1, endIn);
		}
		return root;
	}

protected:
	Node* _root;
};

void Test()
{

	int a[] = { 1, 2, 4, 7, 3, 5, 6, 8 };
	int b[] = { 4, 7, 2, 1, 5, 3, 8, 6 };
	ConstructTree<int> t1(a, b, 8);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值