1. 程式人生 > >根據前序遍歷和中序遍歷,後序遍歷和中序遍歷重構二叉樹

根據前序遍歷和中序遍歷,後序遍歷和中序遍歷重構二叉樹

重構二叉樹目前主要是採取遞迴的方式
只能通過前序,中序 或者 後續,中序進行重構
前序和後序是不能夠重構的,因為在得知根節點後只有中序遍歷才能確定左子樹和右子樹的數目

二叉樹的幾種遍歷
前序遍歷:根結點 —> 左子樹 —> 右子樹

中序遍歷:左子樹—> 根結點 —> 右子樹

後序遍歷:左子樹 —> 右子樹 —> 根結點

層次遍歷:只需按層次遍歷即可

根據前序遍歷和中序遍歷重構二叉樹:

輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。

這裡寫圖片描述
前序遍歷第一位是根節點;
中序遍歷中,根節點左邊的是根節點的左子樹,右邊是根節點的右子樹。
所以,根節點 是{ 1 };
左子樹是:前序{ 2,4,7 } ,中序{ 4,7,2 };
右子樹是:前序{ 3,5,6,8 } ,中序{ 5,3,8,6 };

根據這個我們可以得出二叉樹的形狀
這裡寫圖片描述

這時,如果我們把左子樹和右子樹分別作為新的二叉樹,則可以求出其根節點,左子樹和右子樹。
這樣,一直用這個方式,就可以實現重建二叉樹。

解題步驟
1、前序遍歷的第一個節點即為根節點
2、根據根節點,在中序遍歷中找出左子樹和右子樹,並統計左子樹和右子樹的個數
3、遞迴構建左子樹和右子樹

根據前序遍歷得出根節點,根據中序遍歷確定左子樹和右子樹的個數
這裡寫圖片描述

public class RebuildBinaryTree {
    //假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字
    /*
      前序遍歷第一位是根節點;
      中序遍歷中,根節點左邊的是根節點的左子樹,右邊是根節點的右子樹。
      例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6}。
      首先,根節點 是{ 1 };
      左子樹是:前序{ 2,4,7 } ,中序{ 4,7,2 };
      右子樹是:前序{ 3,5,6,8 } ,中序{ 5,3,8,6 };
      這時,如果我們把左子樹和右子樹分別作為新的二叉樹,則可以求出其根節點,左子樹和右子樹。
     */
public TreeNode reConstructBinaryTree(int [] pre,int [] in) { if(pre==null||in==null){ return null; } TreeNode treeNode=reConstructBinaryTree(pre, in,0,pre.length-1,0,in.length-1); return treeNode; } public TreeNode reConstructBinaryTree(int [] pre,int [] in,int preStart,int preEnd,int inStart,int inEnd) { TreeNode tree=new TreeNode(pre[preStart]); //前序遍歷的第一個是根節點,遞迴時把左子樹和右子樹分別作為新的二叉樹 tree.left=null; tree.right=null; if(preStart==preEnd&&inStart==inEnd){ //說明已經是樹葉節點 return tree; } int root; for(root=inStart;root<inEnd;root++){ //尋找根節點在中序遍歷中的下標 if(pre[preStart]==in[root]){ break; } } int leftLength=root-inStart; //左子樹的長度 int rightLength=inEnd-root; //右子樹的長度 //把左子樹和右子樹分別作為新的二叉樹,則可以求出其根節點,左子樹和右子樹。 if(leftLength>0){ tree.left=reConstructBinaryTree(pre,in,preStart+1,preStart+leftLength,inStart,root-1); } if(rightLength>0){ tree.right=reConstructBinaryTree(pre,in,preStart+1+leftLength,preEnd,root+1,inEnd); } return tree; } }

根據後序遍歷和中序遍歷重構二叉樹:

輸入某二叉樹的後序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的後序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入後序遍歷序列{7,4,2,5,8,3,6,1}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。

思路是一樣的:
這裡寫圖片描述
這裡寫圖片描述
解題步驟
1、後序遍歷的最後一個節點即為根節點
2、根據根節點,在中序遍歷中找出左子樹和右子樹,並統計左子樹和右子樹的個數
3、遞迴構建左子樹和右子樹

public class RebuildBinaryTree {
    //假設輸入的後序遍歷和中序遍歷的結果中都不含重複的數字
    /*
      後序遍歷最一位是根節點;
      中序遍歷中,根節點左邊的是根節點的左子樹,右邊是根節點的右子樹。
      例如輸入後序遍歷序列{7,4,2,5,8,6,3,1}和中序遍歷序列{4,7,2,1,5,3,8,6}。
      首先,根節點 是{ 1 };
      左子樹是:後序{ 7,4,2} ,中序{ 4,7,2 };
      右子樹是:後序{ 5,8,6,3} ,中序{ 5,3,8,6 };
      這時,如果我們把左子樹和右子樹分別作為新的二叉樹,則可以求出其根節點,左子樹和右子樹。
     */
    public TreeNode reConstructBinaryTree(int [] end,int [] in) {
        if(end==null||in==null){
            return null;
        }
        TreeNode treeNode=reConstructBinaryTree(end, in,0,end.length-1,0,in.length-1);
        return treeNode;
    }
    public TreeNode reConstructBinaryTree(int [] end,int [] in,int endStart,int endEnd,int inStart,int inEnd) {
         TreeNode tree=new TreeNode(end[endEnd]);  //後序遍歷的最後一個是根節點,遞迴時把左子樹和右子樹分別作為新的二叉樹
         tree.left=null;
         tree.right=null;
         if(endStart==endEnd&&inStart==inEnd){     //說明已經是樹葉節點
             return tree;
         }
         int root;
         for(root=inStart;root<inEnd;root++){       //尋找根節點在中序遍歷中的下標
             if(end[endStart]==in[root]){
                 break;
             }
         }
         int leftLength=root-inStart;       //左子樹的長度
         int rightLength=inEnd-root;        //右子樹的長度
         //把左子樹和右子樹分別作為新的二叉樹,則可以求出其根節點,左子樹和右子樹。
         if(leftLength>0){
             tree.left=reConstructBinaryTree(end,in,endStart,endStart+leftLength-1,inStart,root-1);
         }
         if(rightLength>0){
             tree.right=reConstructBinaryTree(end,in,root,endEnd-1,root+1,inEnd);
         }
         return  tree;
    }
}