演算法學習之重構二叉樹
阿新 • • 發佈:2018-12-26
背景
根據提供的前序和中序遍歷的結果,重構二叉樹
思路
根據前序和中序的特點,來構造二叉樹。
前序遍歷,根左右,頭一個一定是根結點。
中序遍歷,左根右,根據由前序遍歷確定的根結點,可以確定出左右子樹的中序遍歷結果,以及左右子樹的元素數量。
而後,根據中序遍歷確定的左右子樹的元素數量,可以分出前序遍歷中左右子樹的範圍。
最後,進行遞迴,後序遍歷驗之。
實現
程式碼如下
package practice; import oo.MyTree; public class RebuildBinaryTree { public static void reBuild(MyTree t, int[] pre, int[] in) { int leftLength = -1; // 左子樹長度 int rightLength = -1; // 右子樹長度 int rootData = pre[0]; // 先序遍歷,第一個一定是根結點 t.setData(rootData); for (int i = 0; i < in.length; i++) { if (in[i] == rootData) { leftLength = i;// leftLength = 3 1 break; } } // 中序遍歷,根節點前面的都是左子樹,據此求出左子樹長度 if (leftLength <= 0) { t.setLeft(null); // 如果左子樹長度小於1,說明中序遍歷的頭一個就是根結點,也就是沒有左子樹 } else { // 否則,說明有左子樹,把左子樹的先序遍歷和中序遍歷的結果拷貝,進行遞迴構造 int[] leftInOrder = new int[leftLength]; int[] leftPreOrder = new int[leftLength]; for (int i = 0; i < leftLength; i++) { leftInOrder[i] = in[i]; leftPreOrder[i] = pre[i + 1]; // i+1是因為先序遍歷的第一個是根結點 } t.setLeft(new MyTree()); reBuild(t.getLeft(), leftPreOrder, leftInOrder); // 遞迴 } // 相似的方法構造右子樹 if (leftLength == in.length - 1) { t.setRight(null); // 如果左子樹的長度是中序遍歷的結果-1,那左子樹配上根結點,就是中序遍歷的全部結果,也就是沒有右子樹了 } else { rightLength = in.length - leftLength - 1; // 否則,就是有右子樹,其長度是中序長度-左子樹長度-根結點(也就是-1) // 這個右子樹長度,也可以看成右子樹元素在中序遍歷結果中的偏移量 int[] rightInOrder = new int[rightLength]; int[] rightPreOrder = new int[rightLength]; for (int i = 0; i < rightLength; i++) { rightInOrder[i] = in[i + rightLength]; // 拷貝時要加上偏移量 rightPreOrder[i] = pre[i + rightLength]; } t.setRight(new MyTree()); reBuild(t.getRight(), rightPreOrder, rightInOrder); // 遞迴 } } public static void main(String[] args) { // 前序遍歷{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6} int[] pre = { 1, 2, 4, 7, 3, 5, 6, 8 }; int[] in = { 4, 7, 2, 1, 5, 3, 8, 6 }; MyTree t = new MyTree(); reBuild(t, pre, in); t.travelsInLastOrder(); // 後序遍歷驗證結果 } }
執行結果
由前序和中序可知樹的拓撲圖為
後序遍歷的列印結果為
可見執行沒問題。