题目:输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中不包含重复的数字。
二叉树节点的定义如下:
#include<stdio.h>
#include<stdlib.h>
//二叉树结构的定义
typedef struct BinaryTreeNode{
int m_nValue;
struct BinaryTreeNode *m_pLeft;
struct BinaryTreeNode *m_pRight;
}BinaryTreeNode;
//构建二叉树的核心函数,前序的子串起止位置和中序的子串起止位置
BinaryTreeNode * ConstructCore(int *startPreorder, int *endPreorder, int *startInorder, int *endInorder);
//构建二叉树的函数,前序遍历和中序遍历的起始位置与长度
BinaryTreeNode *Construct(int *preorder, int *inorder, int length)
{
if(preorder == NULL || inorder == NULL || length <= 0) {
printf("invalid input!\n");
return 0;
}
return ConstructCore(preorder, preorder + length -1, inorder, inorder + length - 1);
}
BinaryTreeNode *ConstructCore(int *startPreorder,int *endPreorder,int *startInorder,int *endInorder)
{
//前序遍历的第一个元素,即为根节点
int rootValue = startPreorder[0];
//构建根节点
BinaryTreeNode * root = (BinaryTreeNode*)malloc(sizeof(BinaryTreeNode));
root->m_nValue = rootValue;
root->m_pLeft = root->m_pRight = NULL;
//顺序遍历到最后一个元素
if (startPreorder == endPreorder)
{
//该节点满足是根节点的条件如括号中所示
if (startInorder == endInorder && *startPreorder == *startInorder) {
return root;
} else {
printf("invalid input!\n");
}
}
//根据前序遍历中的根节点的值,在中序遍历中找到根节点
int* rootInorder = startInorder;
while(rootInorder <= endInorder && *rootInorder != rootValue) {
++rootInorder;
}
if(rootInorder == endInorder && *rootInorder != rootValue) {
printf("invalid input!\n");
}
//在中序数组中找到它的左子树的长度
int leftLength = rootInorder - startInorder;
//根据中序遍历中左子树的长度在前序遍历中找到左子树的位置
int* leftPreorderEnd = startPreorder + leftLength;
if(leftLength > 0){
//构建左子树,输入为前序遍历子串的起始地址,中序遍历的起始地址
root->m_pLeft = ConstructCore(startPreorder + 1, leftPreorderEnd, startInorder, rootInorder - 1);
}
if(leftLength < (endPreorder - startPreorder))
{
//构建右子树,输入为前序遍历子串的起始地址,中序遍历的起始地址
root->m_pRight = ConstructCore(leftPreorderEnd + 1,endPreorder, rootInorder + 1, endInorder);
}
return root;
}
void lastOrderTraverse(BinaryTreeNode *root)
{
if(root)
{
lastOrderTraverse(root->m_pLeft);
lastOrderTraverse(root->m_pRight);
printf("%d ",root->m_nValue);
}
}
int main()
{
int preorder[8] = {1, 2, 4, 7, 3, 5, 6, 8};
int inorder[8] = {4, 7, 2, 1, 5, 3, 8, 6};
int length = sizeof(preorder) / sizeof(int);
BinaryTreeNode *tree = Construct(preorder, inorder, length);
printf("后续遍历的顺序为:\n");
lastOrderTraverse(tree);
return 0;
}
下面我们来分析以上代码的结构,主要是对ConstructCore进行分析。
最初建立的两个数组,如图所示,这个指针指向的数据,由于前序遍历可知,我们的根节点是1,那么由中序遍历的结果就知道,472是其左子树上面的值,5386是其右子树的值。
根据前序遍历确定的根节点,在中序遍历当中确定该树的左子树,并且确定左子树的数据个数leftLength,以及在前序遍历中确定左子树的位置。(因为前序遍历会将根节点左子树遍历完,才会去遍历它的右子树,所以根节点后面紧跟的就是左子树的元素了。)
构建左子树,它们的起止地址分别如上图所示,然后就是一直递归调用下去了。
构建右子树,它们的起止地址分别如上图所示,然后就是一直递归调用下去了。