《剑指Offer》面试题:重构二叉树

来源:互联网 发布:杭州市物联网产业数据 编辑:程序博客网 时间:2024/06/05 01:20

题目描述:
输入某二叉树的前序遍历和中序遍历的结果,
请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并输出它的后序遍历序列。

思路
根据前序遍历的数组,arr[0]为根节点,在中序遍历中找到值等于arr[0]的位置index,则index的左边为此节点的左子树,右边为此节点的右子树。于是递归构建该节点的左右子树。

需要考虑的测试用例
1)一个结点的数
2)只有左子树的树
3)只有右子树的树
4)普通的树
5)特殊输入

/*输入:输入可能包含多个测试样例,对于每个测试案例,输入的第一行为一个整数n(1<=n<=1000):代表二叉树的节点个数。输入的第二行包括n个整数(其中每个元素a的范围为(1<=a<=1000)):代表二叉树的前序遍历序列。输入的第三行包括n个整数(其中每个元素a的范围为(1<=a<=1000)):代表二叉树的中序遍历序列。输出:对应每个测试案例,输出一行:如果题目中所给的前序和中序遍历序列能构成一棵二叉树,则输出n个整数,代表二叉树的后序遍历序列,每个元素后面都有空格。如果题目中所给的前序和中序遍历序列不能构成一棵二叉树,则输出”No”。样例输入:81 2 4 7 3 5 6 84 7 2 1 5 3 8 681 2 4 7 3 5 6 84 1 2 7 5 3 8 6样例输出:7 4 2 5 8 6 3 1 No*/ #include<stdio.h>#include<stdlib.h>struct TreeNode{    int mValue;    struct TreeNode *lchild;    struct TreeNode *rchild;};bool canRebuild;/*函数的功能:根据树的前序遍历、中序遍历来重构二叉树。参数的说明@param pRoot:即将重构的Tree的头结点的指针。@param n:节点的个数@param  preTraversal :前序遍历的数组。 @param inTraversal:后序遍历的数组 */void  rebuildBTree(TreeNode **pRoot,int len,int *preTraversal,int *inTraversal){    if(preTraversal==NULL||inTraversal==NULL) {        canRebuild=false;        return ;    }    //    if(len<1){        return;    }    //在中序遍历中找到前序遍历的头结点的左右子结点    int index=-1;     for(int i=0;i<len;i++){        if(preTraversal[0]==inTraversal[i]){            index=i;            break;        }    }     if(index==-1){//这种情况就是没有找到当前根结点在中序遍历的位置。因此不能重构         canRebuild=false;        return;             }    //找到了之后就开始构建此结点    //为当前结点分配空间     (*pRoot)=(TreeNode *)malloc(sizeof(struct TreeNode));    if((*pRoot)==NULL){        exit(EXIT_FAILURE);    }    (*pRoot)->mValue=preTraversal[0];    (*pRoot)->lchild=NULL;    (*pRoot)->rchild=NULL;    //接下来开始构建该结点的左右子树。     rebuildBTree(&((*pRoot)->lchild),index,preTraversal+1,inTraversal);    rebuildBTree(&((*pRoot)->rchild),len-index-1,preTraversal+index+1,inTraversal+index+1); }//按后序遍历输出二叉树 void postTraversal(TreeNode *pRoot){    if(pRoot==NULL){        return;    }    if(pRoot->lchild!=NULL){        postTraversal(pRoot->lchild);    }    if(pRoot->rchild!=NULL){        postTraversal(pRoot->rchild);    }    printf("%d ",pRoot->mValue);}void destoryBTree(TreeNode* pRoot){    if(pRoot==NULL){        return;    }    destoryBTree(pRoot->lchild);    destoryBTree(pRoot->rchild);    if(pRoot->lchild==NULL||pRoot->rchild==NULL){        free(pRoot);        pRoot=NULL;    }    return;}int main(void){    int n;    while(scanf("%d",&n)&&n>0){        int *preTraversal=(int *)malloc(n*sizeof(int));        int *inTraversal=(int *)malloc(n*sizeof(int));        if(preTraversal==NULL||inTraversal==NULL){            exit(EXIT_FAILURE);        }        for(int i=0;i<n;i++){            scanf("%d",preTraversal+i);        }        for(int i=0;i<n;i++){            scanf("%d",inTraversal+i);        }        //重构二叉树        TreeNode *pRoot;        bool canRebuild=true;        rebuildBTree(&pRoot,n,preTraversal,inTraversal) ;        if(canRebuild){            //按后序遍历输出            postTraversal(pRoot);            printf("\n");        }        else{            printf("No\n");        }        //最后销毁二叉树        destoryBTree(pRoot);        free(preTraversal);        preTraversal=NULL;        free(inTraversal);        inTraversal=NULL;     }    return 0;} 

今天和同学聊起这个题,说不知道用Java如何来重建二叉树,于是就写了下,代码如下,2016年8月23日16:20:20

public class RebuildTree2 {    private static boolean canRebuild = true;    private static int[] postOrder ;    private static int indexPost = 0;    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {        if(pre==null||in==null||pre.length!=in.length){            return null;        }        TreeNode head = rebuildHelper(pre,in,pre.length);        if(!canRebuild){//不能重建            return null;        }        return head;    }    private TreeNode rebuildHelper(int[] pre, int[] in, int len) {        if(pre==null||in==null||len<1){            //canRebuild = false;            return null;        }        int val = pre[0];//根节点        //在中序遍历中找到头结点出现的位置        int index = -1;        for(int i=0;i<len;i++){            if(in[i]==val){                index = i;                break;            }        }        if(index==-1){//在中序遍历中没有找到根节点,因此不能重建            canRebuild = false;            return null;        }        //构建当前根节点        TreeNode head = new TreeNode(val);        //接着开始构建根节点的左右子树        //左子树        //先进行数组的拷贝        int len1 = index ;        int[] preNew = new int[len1];        int[] inNew = new int[len1];        for(int i=0;i<len1;i++){            preNew[i] = pre[1+i];            inNew[i] = in[i];        }        head.left = rebuildHelper(preNew, inNew,len1);        //检查左子树是否能够重建        if(!canRebuild){            return null;        }        //右子树        //先进行数组的拷贝        int len2 = len-index-1;        int[] preNew2 = new int[len2];        int[] inNew2 = new int[len2];        for(int i=0;i<len2;i++){            preNew2[i] = pre[index+1+i];            inNew2[i] = in[index+1+i];        }        head.right  = rebuildHelper(preNew2, inNew2,len2);        return head;    }    public static void main(String[] args){        int len = 7;        int[] pre = {1,2,3,4,5,6,7};        int[] in = {3,2,4,1,6,5,7};        postOrder = new int[len];        RebuildTree2 bt = new RebuildTree2();        TreeNode head = bt.reConstructBinaryTree(pre,in);        System.out.println(head.val);        //后序遍历        bt.postOrder(head);         for(int i=0;i<len;i++){            System.out.print(postOrder[i]+" ");        }    }    private  void postOrder(TreeNode head) {        if(head==null){            return ;        }        if(head.left!=null){            postOrder(head.left);        }        if(head.right!=null){            postOrder(head.right);        }        postOrder[indexPost] = head.val;        indexPost++;        //System.out.print(head.val+" ");    }}
1 0