原題連結: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;
}