1. 程式人生 > >二叉樹知道前序和中序求後序,知道中序後序求中序

二叉樹知道前序和中序求後序,知道中序後序求中序

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

首先,我們看看前序、中序、後序遍歷的特性: 
前序遍歷: 
    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<stdio.h>
#include<string.h>
#include<string>
#include<iostream>
using namespace std;
typedef struct node
{
    char data;
    struct node *leftchild;
    struct node *rightchild;
} bitreenode,*bitree;
//*preorders是先序的字串,inorder是中序的字串
void posttraverse(char *preorder,char *inorder,int len)//求後序
{
    if(len==0)return ;
    int rootindex=0;
    node newnode;
    newnode.data=preorder[0];//先序字串的首元素是根節點
    for(rootindex=0; preorder[0]!=inorder[rootindex]; rootindex++);//這一步是找到根節點在中序字串中的位置
    posttraverse(preorder+1,inorder,rootindex);//遞迴遍歷左子樹
    posttraverse(preorder+rootindex+1,inorder+rootindex+1,len-rootindex-1);//遞迴遍歷右子樹
    cout<<*preorder;//列印根節點,為什麼要放在最後呢?因為這是求後序遍歷,如果是求先序遍歷
    //就在遞迴之前列印根節點
}
void pretraverse(char *inorder,char *postorder,int len)//求先序
{
    //類似知先序和中序求後序
    if(len==0)return ;
    int rootindex=0;
    node newnode;
    newnode.data=postorder[len-1];
    cout<<postorder[len-1];
    for(rootindex=0; postorder[len-1]!=inorder[rootindex]; rootindex++);
    pretraverse(inorder,postorder,rootindex);
    pretraverse(inorder+rootindex+1,postorder+rootindex,len-rootindex-1);
}

/*node* BinaryTreeFromOrderings(char* inorder, char* aftorder, int length)//求先序,同時建樹
{
    if(length == 0)
    {
        return NULL;
    }
    node* Node = new node;//Noice that [new] should be written out.
    Node->data= *(aftorder+length-1);

  cout<<Node->data;
    int rootIndex = 0;
    for(;rootIndex < length; rootIndex++)//a variation of the loop
    {
        if(inorder[rootIndex] ==  *(aftorder+length-1))
            break;
    }
    Node->leftchild = BinaryTreeFromOrderings(inorder, aftorder , rootIndex);
    Node->rightchild= BinaryTreeFromOrderings(inorder + rootIndex + 1, aftorder + rootIndex , length - (rootIndex + 1));
    return Node;
}*/
int main()
{
    int i,j,k,cur,last;
    char s1[1000],s2[1000];
    while(scanf("%s",s1)!=EOF)
    {
        scanf("%s",s2);
        //posttraverse(s1,s2,strlen(s1));
        pretraverse(s1,s2,strlen(s1));

        //BinaryTreeFromOrderings(s1,s2,strlen(s1));
        cout<<endl;

    }
    /*
    GDAFEMHZ
    ADEFGHMZ
    前一個是先序,後一個是中序
    */
    //結果AEFDHZMG
/* ADEFGHMZ AEFDHZMG 前一個是中序,後一個是後序 */ //結果GDAFEMHZ return 0; }

二、已知中序和後序遍歷,求前序遍歷

依然是上面的題,這次我們只給出中序和後序遍歷:

中序遍歷:       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

微笑具體程式程式碼已在在上個程式碼中給出

現在咱們具體來分析下以下語句:

    for(rootindex=0; preorder[0]!=inorder[rootindex]; rootindex++);//這一步是找到根節點在中序字串中的位置
    posttraverse(preorder+1,inorder,rootindex);//遞迴遍歷左子樹
    posttraverse(preorder+rootindex+1,inorder+rootindex+1,len-rootindex-1);//遞迴遍歷右子樹
    cout<<*preorder;

rootindex是根節點的位置,用它來表示左子樹和右子樹在字串中的長度

preorder+1是先序左子樹開始的位置,inorder的人是中序左子樹開始的位置,rootindex是左子樹長度

preorder+rootindex+1是右子樹開始的位置,同理inorder+rootindex+1是中序串右子樹開始的位置,len-rootindex-1是長度

要特別注意子樹開始的位置,不能弄錯了:如pretraverse(inorder,postorder,rootindex);

pretraverse(inorder+rootindex+1,postorder+rootindex,len-rootindex-1);後序字串中右子樹開始的位置是postorder+rootindex,不是postorder+index+1!!!!!!