如今有一個問題,已知二叉樹的前序遍歷和中序遍歷:
PreOrder: GDAFEMHZ
InOrder: ADEFGHMZ
咱們如何還原這顆二叉樹,並求出他的後序遍歷?node
咱們基於一個事實:中序遍歷必定是 { 左子樹中的節點集合 },root,{ 右子樹中的節點集合 },前序遍歷的做用就是找到每顆子樹的root位置。ios
算法1
輸入:前序遍歷,中序遍歷
一、尋找樹的root,前序遍歷的第一節點G就是root。
二、觀察前序遍歷GDAFEMHZ,知道了G是root,剩下的節點必然在root的左或右子樹中的節點。
三、觀察中序遍歷ADEFGHMZ。其中root節點G左側的ADEF必然是root的左子樹中的節點,G右側的HMZ必然是root的右子樹中的節點,root不在中序遍歷的末尾或開始就說明根節點的兩顆子樹都不爲空。
四、觀察左子樹ADEF,按照前序遍歷的順序來排序爲DAFE,所以左子樹的根節點爲D,而且A是左子樹的左子樹中的節點,EF是左子樹的右子樹中的節點。
五、一樣的道理,觀察右子樹節點HMZ,前序爲MHZ,所以右子樹的根節點爲M,左子節點H,右子節點Z。算法
觀察發現,上面的過程是遞歸的。先找到當前樹的根節點,而後劃分爲左子樹,右子樹,而後進入左子樹重複上面的過程,而後進入右子樹重複上面的過程。最後就能夠還原一棵樹了:數組
從而獲得PostOrder: AEFDHZMG
改進:
更進一步說,其實,若是僅僅要求寫後續遍歷,甚至不要專門佔用空間保存還原後的樹。只須要用一個數組保存將要獲得的後序,就能實現:spa
算法2
輸入:一個保存後序的數組,前序遍歷,中序遍歷
一、肯定根,放在數組末尾
二、肯定左子樹的索引範圍,放在數組中相同索引的位置。
三、肯定右子樹索引範圍,放在數組中對應索引的位置,恰好能放下。
四、用左子樹的前序遍歷和中序遍歷,把後序遍歷保存在對應索引的位置
五、用左子樹的前序遍歷和中序遍歷,把後序遍歷保存在對應索引的位置code
引伸問題blog
一樣咱們能夠用中序遍歷和後序遍歷還原這顆樹。排序
然而,若是是前序遍歷和後序遍歷,就不可以還原這棵樹了,由於沒法找到中間點,注意下面這兩種狀況:遞歸
兩棵樹的前序是相同的,兩棵樹的後序也是相同的。換句話說,若是有一顆子樹,它的根節點的一個子樹是空樹,那麼就沒法斷定那一個子樹是空樹。索引
上算法1和算法2的代碼:
//算法1 #include <iostream> #include <fstream> #include <string> struct TreeNode { struct TreeNode* left; struct TreeNode* right; char elem; }; TreeNode* BinaryTreeFromOrderings(char* inorder, char* preorder, int length) { if(length == 0) { return NULL; } TreeNode* node = new TreeNode; node->elem = *preorder; int rootIndex = 0; for(;rootIndex < length; rootIndex++) { if(inorder[rootIndex] == *preorder) break; } node->left = BinaryTreeFromOrderings(inorder, preorder +1, rootIndex); node->right = BinaryTreeFromOrderings(inorder + rootIndex + 1, preorder + rootIndex + 1, length - (rootIndex + 1)); std::cout<<node->elem<<std::endl;
free(node); return NULL; } int main(int argc, char** argv){ char* pr="GDAFEMHZ"; char* in="ADEFGHMZ"; BinaryTreeFromOrderings(in, pr, 8); printf("\n"); return 0;}
題目只要求輸出後續遍歷,能夠直接把當前節點的value保存在一個char中。
#include <stdio.h> #include <stdio.h> #include <iostream> using namespace std; struct TreeNode { struct TreeNode* left; struct TreeNode* right; char elem; }; void BinaryTreeFromOrderings(char* inorder, char* preorder, int length) { if(length == 0) { //cout<<"invalid length"; return; } char node_value = *preorder; int rootIndex = 0; for(;rootIndex < length; rootIndex++) { if(inorder[rootIndex] == *preorder) break; } //Left BinaryTreeFromOrderings(inorder, preorder +1, rootIndex); //Right BinaryTreeFromOrderings(inorder + rootIndex + 1, preorder + rootIndex + 1, length - (rootIndex + 1)); cout<<node_value<<endl; return; } int main(int argc, char* argv[]) { printf("Hello World!\n"); char* pr="GDAFEMHZ"; char* in="ADEFGHMZ"; BinaryTreeFromOrderings(in, pr, 8); printf("\n"); return 0; }