洛谷題單指南-二叉樹-P1827 [USACO3.4] 美國血統 American Heritage

江城伍月發表於2024-03-14

原題連結:https://www.luogu.com.cn/problem/P1827

題意解讀:已知二叉樹的中序、前序遍歷結果,求後序遍歷結果。

解題思路:

已知中序、前序(或後序)遍歷的結果,要求後序(或前序)遍歷的結果,本質上就是藉助於已知的前序(或後序)遍歷結果尋找二叉樹的根,

再根據根節點將中序序列劃分成兩部分,左邊是左子樹的中序序列,右邊是右子樹的中序序列,

同樣,前序(或後序)序列除去根節點,也可以劃分成兩部分,前一部分對應左子樹的前序(或後序)序列,後一部分對應右子樹的前序(或後序)序列。

再遞迴的去處理左子樹序列、右子樹序列

輸出每次找到的根的值即可實現遍歷,輸出的位置如在遞迴之前,則為前序遍歷,輸出的位置如在遞迴之後,則為後序遍歷。

注意:此類題,必須知道中序遍歷的結果,如果僅僅有前序、後序是無法計算中序的,因為無法確定左、右子樹序列的範圍。

下面介紹二叉樹還原的過程:

中序:ABEDFCHG

前序:CBADEFGH

第一步:根據前序找到根C

二叉樹形如:

C

/ \

ABEDF(中) HG(中)

BADEF(前) GH(前)

第二步:根據前序找BADEF的根B, GH的根G

二叉樹形如:

C

/ \

B G

/ \ /

A EDF(中) H

DEF(前)

第三步:根據前序找到DEF裡的根D

二叉樹形如:

C

/ \

B G

/ \ /

A D H

/ \

E F

100分程式碼:

#include <bits/stdc++.h>
using namespace std;

string in, pre;

//in_l:中序序列的起點,in_r:中序序列的終點,pre_l:前序序列的起點,pre_r:前序序列的終點
void postorder(int in_l, int in_r, int pre_l, int pre_r)
{
    if(in_l > in_r) return; //沒有節點
    //先透過前序序列找根節點
    int root = pre_l; //根節點位置為前序序列起點

    //在中序序列中找到根節點的位置
    int i = in_l;
    while(in[i] != pre[root]) i++;

    // in_l ~ i-1即左子樹的中序序列, 一共有i-in_l個元素
    // i+1 ~ in_r即右子樹的中序序列, 一共有in_r-i個元素
    // pre_l+1 ~ pre_l+i-in_l即左子樹的前序序列
    // pre_l+i-in_l+1 ~ in_r即右子樹的前序序列
    postorder(in_l, i - 1, pre_l + 1, pre_l + i - in_l); //對左子樹遞迴呼叫找根
    postorder(i + 1, in_r, pre_l + i - in_l + 1, in_r); //對右子樹遞迴呼叫找根
    cout << pre[root]; //遞迴之後輸出根即後序遍歷
}

int main()
{
    cin >> in >> pre;
    postorder(0, in.size() - 1, 0, pre.size() - 1);
    return 0;
}

相關文章