重建二叉樹 及遍歷
阿新 • • 發佈:2018-11-26
題目描述
輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回
劍指offer第63頁
//首先建立一個二叉樹類 /** * 二叉樹定義 * tree.left 左節點 * tree.right 右節點 */ public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } } //solution類,實現重建二叉樹 public class Solution { //主功能函式 public static TreeNode reConstructBinaryTree(int [] pre,int [] in) { if(pre == null || in == null){ return null; } TreeNode mm = reConstructBinaryTreeCore(pre, in, 0, pre.length-1, 0, in.length-1); return mm; } //核心遞迴 public static TreeNode reConstructBinaryTreeCore(int[] pre, int[] in, int preStart, int preEnd, int inStart, int inEnd) { /** * 把前序遍歷的值賦給二叉樹的根節點 * tree.left 左節點 * tree.right 右節點 */ TreeNode tree = new TreeNode(pre[preStart]); tree.left = null; tree.right = null; /** * preStart,preEnd為陣列的索引 * pre[preStart],獲取該二叉樹的前序遍歷節點的值 * */ if (preStart == preEnd && inStart == inEnd) {//如果(preStart == preEnd,說明樹只有一個元素,該元素就是樹唯一的元素 return tree; } int root = 0; //<editor-fold desc="對中序in[]陣列遍歷得到分支"> /** * 由二叉樹的性質 * 由前序遍歷的值pre_i來確定根節點 * 遍歷中序遍歷的值,尋找中序遍歷中的根節點pre_j * 當中序遍歷的值in_j==pre_i時,可以確定該根節點的左右子樹 */ //</editor-fold> for(root= inStart; root < inEnd; root++){ if (pre[preStart] == in[root]) { break; } } //<editor-fold desc="根節點為tree,對左右分支分別使用前序和中序遍歷進行描述並分組,對分組使用核心遞迴方法,得到tree.left // 和tree.right // 然後依次得到tree.left的左右節點...."> /** * 得到中序遍歷的節點的值 * leifLength 左子樹的元素個數(不含根節點) * rightLength 右子樹的元素個數(不含根節點) */ //</editor-fold> int leifLength = root - inStart; int rightLength = inEnd - root; if (leifLength > 0) { //得到左節點的值 tree.left = reConstructBinaryTreeCore(pre, in, preStart+1, preStart+leifLength, inStart, root-1); } if (rightLength > 0) { //得到右節點的值 //下一層遞迴,則會得到tree.right的左或右節點...... tree.right = reConstructBinaryTreeCore(pre, in, preStart+1+leifLength, preEnd, root+1, inEnd); } return tree; } //<editor-fold desc="遍歷測試"> /* //將二叉樹先序遍歷,用於測試結果 public static void preTraverseBinTree(TreeNode node){ if (node==null) { return; } System.out.print(node.val+","); if (node.left!=null) { preTraverseBinTree(node.left); } if(node.right!=null){ preTraverseBinTree(node.right); } } //將二叉樹中序遍歷,用於測試結果 public static void inTraverseBinTree(TreeNode node){ if (node==null) { return; } if (node.left!=null) { inTraverseBinTree(node.left); } System.out.print(node.val+","); if(node.right!=null){ inTraverseBinTree(node.right); } } */ //</editor-fold> //將二叉樹後序遍歷,用於測試結果 public static void postTraverseBinTree(TreeNode node){ if (node==null) { return; } if (node.left!=null) { postTraverseBinTree(node.left); } if(node.right!=null){ postTraverseBinTree(node.right); } System.out.print(node.val+","); } //主函式,用於測試結果 public static void main(String[] args){ int pre[] = {1,2,4,7,3,5,8,9,6}; int in[] = {4,7,2,1,8,5,9,3,6}; TreeNode tree = reConstructBinaryTree(pre, in); //<editor-fold desc="測試"> /* System.out.print("先序遍歷結果: {"); preTraverseBinTree(tree); System.out.println("}"); System.out.print("中序遍歷結果: {"); inTraverseBinTree(tree); System.out.println("}");*/ //</editor-fold> System.out.print("後序遍歷結果: {"); postTraverseBinTree(tree); System.out.println("}"); } }
程式碼較長,可以先簡要分析一下:
1)建立一個二叉樹類
//首先建立一個二叉樹類
/**
* 二叉樹定義
* tree.left 左節點
* tree.right 右節點
*/
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
思路:
a、根據前序遍歷的陣列第一個元素為根節點pre_i,在中序遍歷陣列中找到元素in_j=pre_i;設tree=pre_i
for(root= inStart; root < inEnd; root++){ if (pre[preStart] == in[root]) { break; } }
b、由中序遍歷的思想,pre_i為根節點,可以將二叉樹分為左右子樹,所以pre_j左邊的元素為左子樹中的元素,集合為{L},pre_j右邊的元素為右子樹中的元素,集合為{R}(此時具體組合未知);
int leifLength = root - inStart; int rightLength = inEnd - root; if (leifLength > 0) { //得到左節點的值 tree.left = reConstructBinaryTreeCore(pre, in, preStart+1, preStart+leifLength, inStart, root-1); } if (rightLength > 0) { //得到右節點的值 //下一層遞迴,則會得到tree.right的左或右節點...... tree.right = reConstructBinaryTreeCore(pre, in, preStart+1+leifLength, preEnd, root+1, inEnd); }
c、根據前序遍歷的思想,一定是先根節點,然後遍歷左子樹 (集合等於{L1}) ,再遍歷右子子樹(集合等於{R1}). L與L1元素一致,但排序順序不同
於是對L和L1,使用reConstructBinaryTreeCore(),由L第一個元素得到其子樹的節點tree.left(為父節點),由R得到tree.right.
根據父節點tree.left在L1中的位置,將子樹進行劃分,得到下一級的節點(tree.left).left 和(tree.left).right;
同理,得到(tree.right).left 和(tree.right).right;
d、一直下去,得到最後的左右節點 這樣樹TreeNode就構建完成,由形如 tree.left or right這樣的形式構成
如圖