1. 程式人生 > >[劍指offer學習心得]之:重建二叉樹

[劍指offer學習心得]之:重建二叉樹

題目:輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如:前序遍歷序列{ 1, 2, 4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},重建出下圖所示的二叉樹並輸出它的頭結點。

二叉樹展示

二叉樹的前序遍歷中,第一個數字總是樹的根結點的值。但在中序遍歷中根結點的值就在序列中箭,左子樹的結點的值位於根結點的值的左邊,右子樹的結點的值位於根結點的值的右邊。因此我們需要掃描中序遍歷,才能找到根結點的值。

比如說這個圖啊,前序遍歷的第一個數字1就是根結點的值。掃描中序遍歷序列,就能確定根結點的值的位置。根據中序遍歷的特點,在根結點的值1 前面的3個數字就是左子樹結點的值,位於1後面的數字都是右子樹結點的值。

由於在中序遍歷序列中,3個數字是左子樹結點的值,因此左子樹總共有3個左子結點。同樣,在前序遍歷序列中,根結點後面3個數字就是3個左子樹結點的值,再後面所有數字都是右子樹結點的值。然後就可以分別找到了左右子樹對應的子序列。

既然我們已經分別找到了左右子樹的前序遍歷序列和中序遍歷序列,可以用同樣的方法分別去構建左右子樹。也就是說,接下來的事情可以用遞迴實現。

測試用例

  1. 普通二叉樹(完全二叉樹,不完全二叉樹)
  2. 特殊二叉樹(所有結點都沒有右子結點的二叉樹,所有結點都沒有左子結點的二叉樹,只有一個結點的二叉樹)
  3. 特殊輸入測試(二叉樹的根結點為null、輸入的前序便利序列和中序遍歷序列不匹配)

程式碼


public class Construct {

    /** 
     * 二叉樹節點類 
     */  
    public static class BinaryTreeNode {  
        int value;  
        BinaryTreeNode left;  
        BinaryTreeNode right;  
    }  
    /** 
     * 輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二節樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。 
     * 
     * @param preorder 前序遍歷 
     * @param
inorder 中序遍歷 * @return 樹的根結點 */
public static BinaryTreeNode construct(int[] preorder, int[] inorder) { // 輸入的合法性判斷,兩個陣列都不能為空,並且都有資料,而且資料的數目相同 if (preorder == null || inorder == null || preorder.length != inorder.length || inorder.length < 1) { return null; } return construct(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1); } /** * 輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二節樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。 * * @param preorder 前序遍歷 * @param ps 前序遍歷的開始位置 * @param pe 前序遍歷的結束位置 * @param inorder 中序遍歷 * @param is 中序遍歷的開始位置 * @param ie 中序遍歷的結束位置 * @return 樹的根結點 */ public static BinaryTreeNode construct(int[] preorder, int ps, int pe, int[] inorder, int is, int ie) { // 開始位置大於結束位置說明已經沒有需要處理的元素了 if (ps > pe) { return null; } // 取前序遍歷的第一個數字,就是當前的根結點 int value = preorder[ps]; int index = is; // 在中序遍歷的陣列中找根結點的位置 while (index <= ie && inorder[index] != value) { index++; } // 如果在整個中序遍歷的陣列中沒有找到,說明輸入的引數是不合法的,丟擲異常 if (index > ie) { throw new RuntimeException("Invalid input"); } // 建立當前的根結點,並且為結點賦值 BinaryTreeNode node = new BinaryTreeNode(); node.value = value; // 遞迴構建當前根結點的左子樹,左子樹的元素個數:index-is+1個 // 左子樹對應的前序遍歷的位置在[ps+1, ps+index-is] // 左子樹對應的中序遍歷的位置在[is, index-1] node.left = construct(preorder, ps + 1, ps + index - is, inorder, is, index - 1); // 遞迴構建當前根結點的右子樹,右子樹的元素個數:ie-index個 // 右子樹對應的前序遍歷的位置在[ps+index-is+1, pe] // 右子樹對應的中序遍歷的位置在[index+1, ie] node.right = construct(preorder, ps + index - is + 1, pe, inorder, index + 1, ie); // 返回建立的根結點 return node; } // 中序遍歷二叉樹 public static void printTree(BinaryTreeNode root) { if (root != null) { printTree(root.left); System.out.print(root.value + " "); printTree(root.right); } } // 普通二叉樹 // 1 // / \ // 2 3 // / / \ // 4 5 6 // \ / // 7 8 private static void test1() { int[] preorder = {1, 2, 4, 7, 3, 5, 6, 8}; int[] inorder = {4, 7, 2, 1, 5, 3, 8, 6}; BinaryTreeNode root = construct(preorder, inorder); printTree(root); } // 所有結點都沒有右子結點 // 1 // / // 2 // / // 3 // / // 4 // / // 5 private static void test2() { int[] preorder = {1, 2, 3, 4, 5}; int[] inorder = {5, 4, 3, 2, 1}; BinaryTreeNode root = construct(preorder, inorder); printTree(root); } // 所有結點都沒有左子結點 // 1 // \ // 2 // \ // 3 // \ // 4 // \ // 5 private static void test3() { int[] preorder = {1, 2, 3, 4, 5}; int[] inorder = {1, 2, 3, 4, 5}; BinaryTreeNode root = construct(preorder, inorder); printTree(root); } // 樹中只有一個結點 private static void test4() { int[] preorder = {1}; int[] inorder = {1}; BinaryTreeNode root = construct(preorder, inorder); printTree(root); } // 完全二叉樹 // 1 // / \ // 2 3 // / \ / \ // 4 5 6 7 private static void test5() { int[] preorder = {1, 2, 4, 5, 3, 6, 7}; int[] inorder = {4, 2, 5, 1, 6, 3, 7}; BinaryTreeNode root = construct(preorder, inorder); printTree(root); } // 輸入空指標 private static void test6() { construct(null, null); } // 輸入的兩個序列不匹配 private static void test7() { int[] preorder = {1, 2, 4, 5, 3, 6, 7}; int[] inorder = {4, 2, 8, 1, 6, 3, 7}; BinaryTreeNode root = construct(preorder, inorder); printTree(root); } public static void main(String[] args) { test1(); System.out.println(); test2(); System.out.println(); test3(); System.out.println(); test4(); System.out.println(); test5(); System.out.println(); test6(); System.out.println(); test7(); } }