根据二叉树的前序遍历和中序遍历,重构出二叉树

来源:互联网 发布:视频音乐 制作软件 编辑:程序博客网 时间:2024/05/22 11:58

题目:这道题目是一道面试题,先序遍历和中序遍历以数组的形式给出,要求我们根据这两个条件重构出二叉树。

下图是一棵二叉树

//              6//           /     \//          5       7  //         / \       \//        2   4       8

先序遍历:6,5,2,4,7,8

中序遍历:2,5,4,6,7,8

思路:二叉树先序遍历的定义:1,先输出根结点2,再输出左子树3,再输出右子树,因此先序遍历时,根结点总会出现在数组开头,中序遍历时,根结点可以将二叉树分为左右子树。

因此,重构二叉树的步骤可以用自顶向下的方法:

1,先在先序序列中找到根结点,

2,在中序序列中找到根结点位置,(可以将二叉树分为左子树和右子树)

3.用同样的办法构造左子树

4.用同样的办法构造右子树。

例如:

1.找到根结点6,因此左子树是2,5,4和右子树是7,8

2.找到左边根结点5,可将子二叉树分为2和4,因此左边确定。

3,找到右边根结点7,因此可确定右子树8。

根据四步走可以写出如出代码:

node* Build_Tree(int* prec,int* inorder,int len){//步骤1:新建根结点node* root=new node(prec[0]);//步骤2:在中序遍历中找到根结点索引,分割左右子树int SubTreeLen=0;while(SubTreeLen < len && inorder[SubTreeLen] != prec[0])++SubTreeLen;if(SubTreeLen > 0){//步骤2:重建左子树,并且将根结点root的left指向左子树root->left=Build_Tree(prec+1,inorder,SubTreeLen);}if(len-SubTreeLen-1 > 0){//步骤2:重建右子树,并且将根结点root的left指向右子树root->right=Build_Tree(prec+1+SubTreeLen,inorder+1+SubTreeLen,len-SubTreeLen-1);}return root;}

接下来的步骤就是进行程序测试,利用边界值等去测试程序的健壮性。

可以利用下面的二叉树去测试:

// 普通二叉树//              1//           /     \//          2       3  //         /       / \//        4       5   6//         \         ///          7       8int preorder[length] = {1, 2, 4, 7, 3, 5, 6, 8};int inorder[length] = {4, 7, 2, 1, 5, 3, 8, 6};// 所有结点都没有右子结点//            1//           / //          2   //         / //        3 //       ///      4//     ///    5int preorder[length] = {1, 2, 3, 4, 5};int inorder[length] = {5, 4, 3, 2, 1};// 所有结点都没有左子结点//            1//             \ //              2   //               \ //                3 //                 \//                  4//                   \//                    5int preorder[length] = {1, 2, 3, 4, 5};int inorder[length] = {1, 2, 3, 4, 5};// 树中只有一个结点    int preorder[length] = {1};    int inorder[length] = {1};// 完全二叉树//              1//           /     \//          2       3  //         / \     / \//        4   5   6   7    int preorder[length] = {1, 2, 4, 5, 3, 6, 7};    int inorder[length] = {4, 2, 5, 1, 6, 3, 7};// 输入空指针// 输入的两个序列不匹配    int preorder[length] = {1, 2, 4, 5, 3, 6, 7};    int inorder[length] = {4, 2, 8, 1, 6, 3, 7};

上述测试例子引自于:《剑指Offer——名企面试官精讲典型编程题》

经过测试,当输入空指针和两个序列不匹配时,原始的程序无办法处理,可以针对性处理如下:

#include<iostream>#include <exception>using std::cout;using std::endl;struct node{int value;node* left;node* right;node(int v):value(v),left(NULL),right(NULL){}};node* Build_Tree(int* prec,int* inorder,int len){if(!prec || !inorder || len <=0 ){cout<<"Empty Input!"<<endl;exit(1);//暴力关机}//步骤1:新建根结点node* root=new node(prec[0]);//步骤2:在中序遍历中找到根结点索引,分割左右子树int SubTreeLen=0;while(SubTreeLen < len && inorder[SubTreeLen] != prec[0])++SubTreeLen;if(SubTreeLen == len)//越界了,说明两个数组无法构造出二叉树{cout<<"Wrong Input!"<<endl;exit(1);//暴力关机}if(SubTreeLen > 0){//步骤2:重建左子树,并且将根结点root的left指向左子树root->left=Build_Tree(prec+1,inorder,SubTreeLen);}if(len-SubTreeLen-1 > 0){//步骤2:重建右子树,并且将根结点root的left指向右子树root->right=Build_Tree(prec+1+SubTreeLen,inorder+1+SubTreeLen,len-SubTreeLen-1);}return root;}void prec_tree_walk(node* z){if(!z)return ;cout<<z->value<<' ';prec_tree_walk(z->left);prec_tree_walk(z->right);}void inorder_tree_walk(node* z){if(!z)return ;inorder_tree_walk(z->left);cout<<z->value<<' ';inorder_tree_walk(z->right);}int main(){int prec[] = {1, 2, 4, 7, 3, 5, 6, 8};int Inorder[] = {4, 7, 2, 1, 5, 3, 8, 6};int len=sizeof(prec)/sizeof(prec[0]);node* root=Build_Tree(prec,Inorder,len);prec_tree_walk(root);cout<<endl;inorder_tree_walk(root);return 0;}
中途发现的编译错误记录如下:点击打开链接


原创粉丝点击