【演算法】二叉樹前序、中序、後序遍歷相互求法(轉)
二叉樹前序、中序、後序遍歷相互求法
今天來總結下二叉樹前序、中序、後序遍歷相互求法,即如果知道兩個的遍歷,如何求第三種遍歷方法,比較笨的方法是畫出來二叉樹,然後根據各種遍歷不同的特性來求,也可以程式設計求出,下面我們分別說明。
首先,我們看看前序、中序、後序遍歷的特性:
前序遍歷:
1.訪問根節點
2.前序遍歷左子樹
3.前序遍歷右子樹
中序遍歷:
1.中序遍歷左子樹
2.訪問根節點
3.中序遍歷右子樹
後序遍歷:
1.後序遍歷左子樹
2.後序遍歷右子樹
3.訪問根節點
一、已知前序、中序遍歷,求後序遍歷
例:
前序遍歷: GDAFEMHZ
中序遍歷: ADEFGHMZ
畫樹求法:第一步,根據前序遍歷的特點,我們知道根結點為G
第二步,觀察中序遍歷ADEFGHMZ。其中root節點G左側的ADEF必然是root的左子樹,G右側的HMZ必然是root的右子樹。
第三步,觀察左子樹ADEF,左子樹的中的根節點必然是大樹的root的leftchild。在前序遍歷中,大樹的root的leftchild位於root之後,所以左子樹的根節點為D。
第四步,同樣的道理,root的右子樹節點HMZ中的根節點也可以通過前序遍歷求得。在前序遍歷中,一定是先把root和root的所有左子樹節點遍歷完之後才會遍歷右子樹,並且遍歷的左子樹的第一個節點就是左子樹的根節點。同理,遍歷的右子樹的第一個節點就是右子樹的根節點。
第五步,觀察發現,上面的過程是遞迴的。先找到當前樹的根節點,然後劃分為左子樹,右子樹,然後進入左子樹重複上面的過程,然後進入右子樹重複上面的過程。最後就可以還原一棵樹了。該步遞迴的過程可以簡潔表達如下:
1 確定根,確定左子樹,確定右子樹。
2 在左子樹中遞迴。
3 在右子樹中遞迴。
4 列印當前根。
那麼,我們可以畫出這個二叉樹的形狀:
那麼,根據後序的遍歷規則,我們可以知道,後序遍歷順序為:AEFDHZMG
程式設計求法:(依據上面的思路,寫遞迴程式)
1 #include <iostream> 2 #include <fstream> 3 #include <string> 4 5 struct TreeNode 6 { 7 struct TreeNode* left; 8 struct TreeNode* right; 9 char elem; 10 }; 11 12 void BinaryTreeFromOrderings(char* inorder, char* preorder, int length) 13 { 14 if(length == 0) 15 { 16 //cout<<"invalid length"; 17 return; 18 } 19 TreeNode* node = new TreeNode;//Noice that [new] should be written out. 20 node->elem = *preorder; 21 int rootIndex = 0; 22 for(;rootIndex < length; rootIndex++) 23 { 24 if(inorder[rootIndex] == *preorder) 25 break; 26 } 27 //Left 28 BinaryTreeFromOrderings(inorder, preorder +1, rootIndex); 29 //Right 30 BinaryTreeFromOrderings(inorder + rootIndex + 1, preorder + rootIndex + 1, length - (rootIndex + 1)); 31 cout<<node->elem<<endl; 32 return; 33 } 34 35 36 int main(int argc, char* argv[]) 37 { 38 printf("Hello World!\n"); 39 char* pr="GDAFEMHZ"; 40 char* in="ADEFGHMZ"; 41 42 BinaryTreeFromOrderings(in, pr, 8); 43 44 printf("\n"); 45 return 0; 46 }
輸出的結果為:AEFDHZMG
二、已知中序和後序遍歷,求前序遍歷
依然是上面的題,這次我們只給出中序和後序遍歷:
中序遍歷: ADEFGHMZ
後序遍歷: AEFDHZMG
畫樹求法:第一步,根據後序遍歷的特點,我們知道後序遍歷最後一個結點即為根結點,即根結點為G。
第二步,觀察中序遍歷ADEFGHMZ。其中root節點G左側的ADEF必然是root的左子樹,G右側的HMZ必然是root的右子樹。
第三步,觀察左子樹ADEF,左子樹的中的根節點必然是大樹的root的leftchild。在前序遍歷中,大樹的root的leftchild位於root之後,所以左子樹的根節點為D。
第四步,同樣的道理,root的右子樹節點HMZ中的根節點也可以通過前序遍歷求得。在前後序遍歷中,一定是先把root和root的所有左子樹節點遍歷完之後才會遍歷右子樹,並且遍歷的左子樹的第一個節點就是左子樹的根節點。同理,遍歷的右子樹的第一個節點就是右子樹的根節點。
第五步,觀察發現,上面的過程是遞迴的。先找到當前樹的根節點,然後劃分為左子樹,右子樹,然後進入左子樹重複上面的過程,然後進入右子樹重複上面的過程。最後就可以還原一棵樹了。該步遞迴的過程可以簡潔表達如下:
1 確定根,確定左子樹,確定右子樹。
2 在左子樹中遞迴。
3 在右子樹中遞迴。
4 列印當前根。
這樣,我們就可以畫出二叉樹的形狀,如上圖所示,這裡就不再贅述。
那麼,前序遍歷: GDAFEMHZ
程式設計求法:(並且驗證我們的結果是否正確)
#include <iostream> #include <fstream> #include <string> struct TreeNode { struct TreeNode* left; struct TreeNode* right; char elem; }; TreeNode* BinaryTreeFromOrderings(char* inorder, char* aftorder, int length) { if(length == 0) { return NULL; } TreeNode* node = new TreeNode;//Noice that [new] should be written out. node->elem = *(aftorder+length-1); std::cout<<node->elem<<std::endl; int rootIndex = 0; for(;rootIndex < length; rootIndex++)//a variation of the loop { if(inorder[rootIndex] == *(aftorder+length-1)) break; } node->left = BinaryTreeFromOrderings(inorder, aftorder , rootIndex); node->right = BinaryTreeFromOrderings(inorder + rootIndex + 1, aftorder + rootIndex , length - (rootIndex + 1)); return node; } int main(int argc, char** argv) { char* af="AEFDHZMG"; char* in="ADEFGHMZ"; BinaryTreeFromOrderings(in, af, 8); printf("\n"); return 0; }
輸出結果:GDAFEMHZ
三、已知前序、後序遍歷,求中序遍歷
(這個結果不唯一,你有什麼想法呢?)