劍指offer第二版面試題6:重建二叉樹(JAVA版)

題目:輸入某二叉樹的前序遍歷和中序遍歷的結果,請從新構造出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中不包含重複的數字。例如輸入的前序遍歷序列爲{1,2,4,7,3,5,6,8}和中序遍歷爲{4,7,2,1,5,3,6,8},則重建出二叉樹並輸出它的頭結點。ui

前序遍歷:根節點--》左節點--》右節點this

中序遍歷:左節點--》根節點--》右節點spa

後序遍歷:左節點--》右節點--》根節點3d

在二叉樹的前序遍歷序列中,第一個數字老是樹的根節點的值。但在中序遍歷中,根節點的值在序列的中間,左子樹的結點的值位於根節點的值的左邊,而右子樹的結點的值位於根節點的右邊。所以咱們須要掃描中序遍歷序列,才能找到根節點的值。code

如圖所示,前序遍歷序列的第一個數字1就是根節點的值。掃描中序遍歷序列,就能肯定根節點的值的位置。根據中序遍歷的特色,在根節點的值1前面3個數字都是左子樹結點的值,位於1後面的數字都是右子樹結點的值。blog

 

因爲中序遍歷序列中,有3個數字是左子樹結點的值,所以左子樹總共有3個左子結點。一樣,在前序遍歷的序列中,根節點後面的3個數字就是3個左子樹結點的值,再後面的全部數字都是右子樹結點的值。這樣咱們就在前序遍歷和中序遍歷兩個序列中,分別找到了左右子樹對應的子序列。遞歸

 

而後再根據左子樹的前序遍歷和中序遍歷找出根節點和左右子樹,能夠使用遞歸來完成,每次獲得根節點get

用左子樹來舉例:class

第二次:二叉樹

前序:247

中序:472

根節點2,由中序可知沒有右節點

第三次:

前序:47

中序:47

根節點:4

沒有了左子樹,7爲4的右節點

 

代碼以下:

/**
 * 樹節點
 */
class BinaryTreeNode {
    int value;
    BinaryTreeNode leftNode;
    BinaryTreeNode rightNode;
    public BinaryTreeNode(int value){
        this.value=value;
    }
    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }
    public BinaryTreeNode getLeftNode() {
        return leftNode;
    }
    public void setLeftNode(BinaryTreeNode leftNode) {
        this.leftNode = leftNode;
    }
    public BinaryTreeNode getRightNode() {
        return rightNode;
    }
    public void setRightNode(BinaryTreeNode rightNode) {
        this.rightNode = rightNode;
    }
    
}

public class RebuildTree {
    /**
     * 根據前序遍歷和中序遍歷重建二叉樹
     * */
    public static BinaryTreeNode rebuildTree(int[] preOrder, int[] inOrder){
        if (preOrder == null || inOrder == null || preOrder.length == 0 || inOrder.length == 0 || preOrder.length != inOrder.length) {
            return null;
        }
        //根節點
        BinaryTreeNode root=new BinaryTreeNode(preOrder[0]);
        root.setLeftNode(null);
        root.setRightNode(null);
        //左子樹節點的個數
        int leftNum=0;
        for(int i=0;i<inOrder.length;i++){
            if(inOrder[i]==root.getValue()){
                break;
            }else{
                leftNum++;
            }
        }
        //右子樹節點的個數
        int rightNum=inOrder.length-1-leftNum;
        
        //重建左子樹
        while(leftNum>0){
            //用來存放左子樹的前序遍歷
            int leftPreOrder[]=new int[leftNum];
            //用來存放左子樹的中序遍歷
            int leftInOrder[]=new int[leftNum];
            //賦值給左子樹每一個節點值,把左子樹再獨立成一棵樹
            for(int i=0;i<leftNum;i++){
                leftPreOrder[i]=preOrder[i+1];
                leftInOrder[i]=inOrder[i];
            }
            BinaryTreeNode leftRoot=rebuildTree(leftPreOrder, leftInOrder);
            root.setLeftNode(leftRoot);
        }
        //重建右子樹
        while(rightNum>0){
            //右子樹的前序遍歷
            int rightPreOrder[]=new int[rightNum];
            //右子樹的中序遍歷
            int rightInOrder[]=new int[rightNum];
            //賦值

            for(int i=0;i<rightNum;i++){
                rightPreOrder[i]=preOrder[i+1+leftNum];
                rightInOrder[i]=preOrder[i+1+leftNum];
            }
            BinaryTreeNode rightNode=rebuildTree(rightPreOrder, rightInOrder);
            root.setRightNode(rightNode);
        }
        
        return root;
    }
    
    public static void main(String[] args) {
        // 二叉樹的先序序列
        int[] preOrder = { 1, 2, 4, 7, 3, 5, 6, 8 };
        // 二叉樹的中序序列
        int[] inOrder = { 4, 7, 2, 1, 5, 3, 8, 6 };
        BinaryTreeNode root = rebuildTree(preOrder, inOrder);
    }
}
相關文章
相關標籤/搜索