1、题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如图所示的二叉树并输出他的头结点。二叉树的节点的定义如下:
struct BinaryTreeNode{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
2、解题思路
在二叉树的前序遍历中,第一个数字总是树的根节点的值。
在中序遍历序列中,根节点的值在序列的中间,左子树的结点的值位于根节点的值的左边,而右子树的结点的值位于根结点的值的右边。
因此我们需要扫描中序遍历序列,才能找到根节点的值。
【步骤】:
- 利用递归来实现,每次依次取出前序遍历序列的节点做为根节点;
- 遍历中序遍历序列,找到根节点所在的位置;
- 判断下次递归的根节点是本次节点的左子树还是右子树(在中序遍历序列中,根据下次递归的节点会是本次节点的右边还是左边来决定);
- 递归的进行创建子树;
3、源码
//二叉树节点
template<class T>
struct BinTreeNode
{
BinTreeNode(const T& data)
:_data(data)
, _pLeft(NULL)
, _pRight(NULL)
{}
T _data;
BinTreeNode<T>* _pLeft;
BinTreeNode<T>* _pRight;
};
typedef BinTreeNode<T> Node;
typedef Node* pNode;
//根据前序,中序遍历结果重建二叉树
pNode Construct(T* PreOrder, T* InOrder, T len){
if (PreOrder == NULL || InOrder == NULL || len < 0)
return NULL;
return _ConstructCore(PreOrder, PreOrder + len - 1, InOrder, InOrder + len - 1);
}
//根据前序,中序遍历结果重建二叉树
pNode _ConstructCore(T* PreOrderStart, T* PreOrderEnd, T* InOrderStart, T* InOrderEnd){
//先从前序遍历列表里拿到根节点,并创建根节点
T rootValue = PreOrderStart[0];
pNode root = new Node(rootValue);
if (PreOrderStart == PreOrderEnd){
if (InOrderStart == InOrderEnd && *PreOrderStart == *InOrderStart)
return root;
else
throw exception("Invalid input.");
}
//在中序遍历中找到根节点的值
int* rootInOrder = InOrderStart;
while (rootInOrder <= InOrderEnd && *rootInOrder != rootValue)
++rootInOrder;
//在整个中序遍历列表里都没有找到前序遍历的根
if (rootInOrder == InOrderEnd && *rootInOrder != rootValue)
throw exception("invalid input.");
int leftlen = rootInOrder - InOrderStart;
int* leftPreorderEnd = PreOrderStart + leftlen;
if(leftlen > 0){
//构建左子树
root->_pLeft = _ConstructCore(PreOrderStart + 1, leftPreorderEnd, InOrderStart, rootInOrder - 1);
}
if (leftlen < PreOrderEnd - PreOrderStart){
//构建右子树
root->_pRight = _ConstructCore(leftPreorderEnd + 1, PreOrderEnd, rootInOrder + 1, InOrderEnd);
}
return root;
}