1. 程式人生 > >根據遍歷序列還原二叉樹

根據遍歷序列還原二叉樹

首先看一道PTA上的題目:

7-1 根據後序和中序遍歷輸出先序遍歷 (25 分)

本題要求根據給定的一棵二叉樹的後序遍歷和中序遍歷結果,輸出該樹的先序遍歷結果。

輸入格式:

第一行給出正整數N(≤30),是樹中結點的個數。隨後兩行,每行給出N個整數,分別對應後序遍歷和中序遍歷結果,數字間以空格分隔。題目保證輸入正確對應一棵二叉樹。

輸出格式:

在一行中輸出Preorder:以及該樹的先序遍歷結果。數字間有1個空格,行末不得有多餘空格。

輸入樣例:

7
2 3 1 5 7 6 4
1 2 3 4 5 6 7

輸出樣例:

Preorder: 4 1 3 2 6 5 7

已知後序遍歷和中序遍歷,如何求出二叉樹呢?我們知道,後序遍歷的順序是“左、右、根”,因此,最後一個“4”必然是樹根。在中序序列中找到這個“4”,它將中序序列分成兩部分:“123”和“567”。於是我們就知道,這棵樹的左子樹含有1、2、3三個元素,右子樹含有5、6、7三個元素。即:

1 2 3   4   5 6 7

然後,我們看後序序列倒數第二個元素“6”,它必然是樹的右子樹的根節點。再到中序序列中找到6,它將右子樹分成“5”和“7”兩個部分,而後序序列倒數第三個元素為7,則7是右子樹的右子樹的根節點……以此類推,就可以將二叉樹還原。

但是,人用這種方法來做題是可以的,用程式碼卻不太容易實現,以下方法更適合程式碼實現:

首先找到根節點4,它將中序序列分成左(123)右(567)子樹,然後,我們對比觀察後序序列和中序序列:

2 3 1   5 7 6   4

1 2 3   4   5 6 7

不難發現規律:如果左子樹有m個元素,右子樹有n個元素,則後序序列中,前m個元素恰好對應左子樹,除去這m個元素以及根節點(最後一個元素),剩下的元素恰好與右子樹對應。

於是問題就遞迴轉化為:

已知後序序列為 2 3 1,中序序列為1 2 3,求這棵樹(即原樹的左子樹);

已知後序序列為 5 7 6,中序序列為5 6 7,求這棵樹(即原樹的右子樹)。

同樣的,已知前序序列和中序序列也可用類似方法解決。

//標頭檔案包含
#include<stdlib.h>
#include<stdio.h>
#include<malloc.h>

//函式狀態碼定義
#define TRUE       1
#define FALSE      0
#define OK         1
#define ERROR      0
#define OVERFLOW   -1
#define INFEASIBLE -2

typedef int Status;

//二叉連結串列儲存結構定義
typedef int TElemType;
typedef struct BiTNode{
    TElemType data;
    struct BiTNode  *lchild, *rchild; 
} BiTNode, *BiTree;

BiTree CreateBiTree(int *in,int *post, int n)
{
    if(n<=0)
        return NULL;
    int *p = in;
    while(p)
    {
        if(*p==*(post+n-1))
            break;
        p++;
    }
    BiTree T = (BiTree)malloc(sizeof(BiTNode));

    T->data = *p;
    int len = p-in;
    T->lchild = CreateBiTree(in,post,len);
    T->rchild = CreateBiTree(p+1,post+len,n-len-1);
    return T;
}
Status PreOrderTraverse(BiTree T)
{
    if(!T)
        return OK;
    else 
    {
        printf(" %d",T->data);
        PreOrderTraverse(T->lchild);
        PreOrderTraverse(T->rchild);
    }
    return OK;
}

int main()
{
    int in[35],post[35];
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&post[i]);
    for(int i=0;i<n;i++)
        scanf("%d",&in[i]);
    BiTree T;
    T = CreateBiTree(in,post,n);
    printf("Preorder:");
    PreOrderTraverse(T);
    return 0;
}