二叉樹前序、中序、后序遍歷相互求法


今天來總結下二叉樹前序、中序、后序遍歷相互求法,即如果知道兩個的遍歷,如何求第三種遍歷方法,比較笨的方法是畫出來二叉樹,然后根據各種遍歷不同的特性來求,也可以編程求出,下面我們分別說明。

總結一下三種遍歷方式的特征: 
前序:開頭是頭結點 
中序:根據頭結點划分左右子樹的元素 
后序:末尾是頭結點

首先,我們看看前序、中序、后序遍歷的特性:

前序遍歷:

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

編程求法:(依據上面的思路,寫遞歸程序)

  #include <iostream> 
  #include <fstream> 
  #include <string> 

  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;
     }
   TreeNode* node = new TreeNode;//Noice that [new] should be written out.
   node->elem = *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->elem<<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;
 }

輸出的結果為: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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM