面试题7:重建二叉树
1、题目
2、分析
3、测试代码
4、测试结果如下
- 给出二叉树的前序遍历和中序遍历,或者后序遍历和中序遍历就可以构建出该二叉树;
- 若仅仅给出前序遍历和后序遍历无法构建出一颗二叉树
1、题目:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字;
例如:
输入前序遍历序列{1, 2, 4, 7, 3, 5, 6, 8},
它的中序遍历序列{4, 7, 2, 1, 5, 3, 8, 6},
则重建出如下所示:
2、分析:
根据前序遍历序列我们可以得出,前序中第一个数字(1) 就是该树的根节点,那么,在中序遍历中,(1)为中间节点的位置,在(1)前面的所有数字为该树的左子树中的所有节点(4,7,2),在(1)右面的所有数字,为右子树的所有节点(5,3,8,6);再根据同样的方法寻求左右子树的节点;在前序遍历中(1)的左孩子为(2)那么,在中序遍历中,(2)的前面(4,7)为它左子树的节点,(2)的后面没有数字,所以(2)没有右孩子;在前序遍历中,(2)的左孩子为(4),在中序遍历中,(4)的前面没有数字,代表(4)没有左孩子,(4)的后面为(7),则(7)为(4)的右孩子,到这里,根节点(1)的左子树就全部构建完成,其右子树构建跟左子树的方式一样,这里不再赘述;
3、测试代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct BinTreeNode
{
int _value;
BinTreeNode *_pLeft;
BinTreeNode *_pRight;
};
//二叉树的基本操作
BinTreeNode* BuyBTNode(int data)//创建节点
{
BinTreeNode* node = (BinTreeNode*)malloc(sizeof(BinTreeNode));
node->_value = data;
node->_pLeft = NULL;
node->_pRight = NULL;
return node;
}
void DestroyTree(BinTreeNode* root)//销毁二叉树
{
if (root == NULL)
return;
DestroyTree(root->_pLeft);
DestroyTree(root->_pRight);
free(root);
}
//========================================================
BinTreeNode* constructcore( int*startpre, int* endpre, int*startin, int*endin )
{
int rootvalue = startpre[0];
BinTreeNode* root = new BinTreeNode();
root->_value = rootvalue;
root->_pLeft = root->_pRight = NULL;
//只有根节点
if(startpre == endpre )
{
if(startin == endin && *startpre == *startin)
{
return root;
}
else printf("无效的输入\n");
}
//在中序遍历中找到根节点的值
int* rootin = startin;
while(rootin <= endin && *rootin != rootvalue )
{
++rootin;
}
if(rootin == endin &&*rootin!= rootvalue)
{
printf("无效的输入\n");
}
int leftlength = rootin - startin;
int* leftPreEnd = startpre + leftlength;
if(leftlength > 0)
{
//构建左子树
root->_pLeft = constructcore(startpre+1,leftPreEnd,startin,rootin-1);
}
if(leftlength <( endpre -startpre) )
{//构建右子树
root->_pRight = constructcore(leftPreEnd+1,endpre,rootin+1,endin);
}
return root;
}
BinTreeNode* construct(int* pre,int* in , int length)
{
if(pre == NULL || in == NULL||length <= 0)
{
return NULL;
}
return constructcore(pre, pre+length-1,in,in+length-1);
}
//=========================测试代码===========================
//************************************************************
//============================================================
void test(int* preorder,int* inorder,int length)
{
printf("前序遍历为: ");
for (int i = 0; i < length; ++i)
printf("%d ", preorder[i]);
printf("\n");
printf("中序遍历为: ");
for (int i = 0; i < length; ++i)
printf("%d ", inorder[i]);
printf("\n");
BinTreeNode* root = construct(preorder, inorder, length);
printf("\n");
DestroyTree(root);
}
// 普通二叉树
// 1
// / \
// 2 3
// / / \
// 4 5 6
// \ /
//
void Test1()
{
const int length = 8;
int preorder[length] = { 1, 2, 4, 7, 3, 5, 6, 8 };
int inorder[length] = { 4, 7, 2, 1, 5, 3, 8, 6 };
test(preorder,inorder,length);
}
// 所有结点都没有右子结点
// 1
// /
// 2
// /
// 3
// /
// 4
// /
// 5
void Test2()
{
const int length = 5;
int preorder[length] = {1, 2, 3, 4, 5};
int inorder[length] = {5, 4, 3, 2, 1};
test(preorder,inorder,length);
}
// 所有结点都没有左子结点
// 1
// \
// 2
// \
// 3
// \
// 4
// \
// 5
void Test3()
{
const int length = 5;
int preorder[length] = {1, 2, 3, 4, 5};
int inorder[length] = {1, 2, 3, 4, 5};
test(preorder,inorder,length);
}
// 树中只有一个结点
void Test4()
{
const int length = 1;
int preorder[length] = {1};
int inorder[length] = {1};
test(preorder,inorder,length);
}
// 完全二叉树
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
void Test5()
{
const int length = 7;
int preorder[length] = {1, 2, 4, 5, 3, 6, 7};
int inorder[length] = {4, 2, 5, 1, 6, 3, 7};
test(preorder,inorder,length);
}
int main()
{
Test1();
Test2();
Test3();
Test4();
Test5();
return 0;
}