【題集】二叉樹的遍歷各種題型彙總

例1:給定一棵二叉樹的後序遍歷和中序遍歷,請你輸出其層序遍歷的序列。html

題目連接:https://www.patest.cn/contests/gplt/L2-006c++

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100 + 10;
int post[MAXN], in[MAXN];
int lchild[MAXN], rchild[MAXN];
vector<int> ans;
int dfs(int pL, int pR, int iL, int iR, int root){
    if(pL > pR) return 0;
    int id = iL;
    while(in[id] != root) ++id;
    int cnt = id - iL;
    lchild[root] = dfs(pL, pL + cnt - 1, iL, id - 1, post[pL + cnt - 1]);
    rchild[root] = dfs(pL + cnt, pR - 1, id + 1, iR, post[pR - 1]);
    return root;
}
void bfs(int root){
    queue<int> q;
    q.push(root);
    while(!q.empty()){
        int x = q.front();
        ans.push_back(x);
        q.pop();
        if(lchild[x]) q.push(lchild[x]);
        if(rchild[x]) q.push(rchild[x]);
    }
}
int main(){
    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]);
    }
    int root = post[N - 1];
    dfs(0, N - 1, 0, N - 1, root);
    bfs(root);
    int len = ans.size();
    for(int i = 0; i < len; ++i){
        printf("%d", ans[i]);
        if(i == len - 1) printf("\n");
        else printf(" ");
    }
    return 0;
}

例2:已知前序遍歷和中序遍歷,求後序遍歷。數組

題目連接:https://www.patest.cn/contests/pat-a-practise/1138post

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 50000 + 10;
int pre[MAXN], in[MAXN];
vector<int> ans;
void dfs(int pL, int pR, int iL, int iR, int root){
    if(pL > pR) return;
    int id = iL;
    while(in[id] != root) ++id;
    int cnt = id - iL;
    dfs(pL + 1, pL + cnt, iL , id - 1, pre[pL + 1]);
    dfs(pL + cnt + 1, pR, id + 1, iR, pre[pL + cnt + 1]);
    ans.push_back(root);
}
int main(){
    int N;
    scanf("%d", &N);
    for(int i = 0; i < N; ++i){
        scanf("%d", &pre[i]);
    }
    for(int i = 0; i < N; ++i){
        scanf("%d", &in[i]);
    }
    int root = pre[0];
    dfs(0, N - 1, 0, N - 1, root);
    printf("%d\n", ans[0]);
    return 0;
}

另外一種作法:spa

由於輸出的是後序遍歷(左右中)第一個元素,所以對於某元素,code

若是有左子樹的話,就不用研究右子樹了;htm

若是沒有左子樹,就研究右子樹;blog

若是左右子樹都沒有,就研究他自己。(遇到的第一個葉子結點就是答案)get

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 50000 + 10;
int pre[MAXN], in[MAXN];
map<int, int> mp;
void dfs(int pL, int pR, int iL, int iR, int root){
    if(pL > pR) return;
    int id = mp[root];
    int cnt = id - iL;
    if(iL != id){
        dfs(pL + 1, pL + cnt, iL, id - 1, pre[pL + 1]);
    }
    else if(iR != id){
        dfs(pL + cnt + 1, pR, id + 1, iR, pre[pL + cnt + 1]);
    }
    else{
        printf("%d\n", root);
        return;
    }
}
int main(){
    int N;
    scanf("%d", &N);
    for(int i = 0; i < N; ++i){
        scanf("%d", &pre[i]);
    }
    for(int i = 0; i < N; ++i){
        scanf("%d", &in[i]);
        mp[in[i]] = i;
    }
    int root = pre[0];
    dfs(0, N - 1, 0, N - 1, root);
    return 0;
} 

 例3:已知前序遍歷和後序遍歷,求中序遍歷。it

思路:前序遍歷的第一個元素是根。

若只有左子樹,則前序遍歷的第二個元素和後序遍歷的倒數第二個元素相同,且都是左子樹的根;

若只有右子樹,則前序遍歷的第二個元素和後序遍歷的倒數第二個元素相同,且都是右子樹的根;

若既有左子樹又有右子樹,則前序遍歷的第二個元素是左子樹的根,後序遍歷的倒數第二個元素是右子樹的根;

即,若前序遍歷的第二個元素和後序遍歷的倒數第二個元素相同,則對於當前根結點來講有兩種可能,要麼只有左子樹,要麼只有右子樹。這兩種狀況下,前序遍歷是相同的,後序遍歷也是相同的,但中序遍歷不一樣。

(1)求任意一種中序遍歷。

題目連接:https://www.patest.cn/contests/pat-a-practise/1119

#include<cstdio>
#include<vector>
#include<map>
using namespace std;
const int MAXN = 30 + 10;
int pre[MAXN], pos[MAXN];
int cnt;
map<int, int> mp1;
map<int, int> mp2;
vector<int> ans;
void dfs(int prL, int prR, int poL, int poR, int root){
    if(prL > prR) return;
    if(prL == prR){
        ans.push_back(root);
        return;
    }
    int tmp1 = pre[prL + 1];
    int tmp2 = pos[poR - 1];
    if(tmp1 != tmp2){
        dfs(mp1[tmp1], mp1[tmp2] - 1, poL, mp2[tmp1], pre[mp1[tmp1]]);
        ans.push_back(root);
        dfs(mp1[tmp2], prR, mp2[tmp1] + 1, poR - 1, pre[mp1[tmp2]]);
    }
    else{
        ++cnt;
        dfs(mp1[tmp1], prR, poL, mp2[tmp1], pre[mp1[tmp1]]);
        ans.push_back(root);
    }
}
int main(){
    int N;
    scanf("%d", &N);
    for(int i = 0; i < N; ++i){
        scanf("%d", &pre[i]);
        mp1[pre[i]] = i;
    }
    for(int i = 0; i < N; ++i){
        scanf("%d", &pos[i]);
        mp2[pos[i]] = i;
    }
    int root = pre[0];
    dfs(0, N - 1, 0, N - 1, root);
    if(cnt >= 1) printf("No\n");
    else printf("Yes\n");
    int len = ans.size();
    for(int i = 0; i < len; ++i){
        printf("%d", ans[i]);
        if(i == len - 1) printf("\n");
        else printf(" ");
    }
    return 0;
}

 (2)求中序遍歷可能的種數。

題目連接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1832

思路:運算結果涉及高精度計算。

#include<cstdio>
#include<vector>
#include<map>
using namespace std;
const int MAXN = 10000 + 10;
const int MOD = 1000000000;
int pre[MAXN], pos[MAXN];
int cnt;
map<int, int> mp1;
map<int, int> mp2;
int ans[MAXN];
void dfs(int prL, int prR, int poL, int poR){
    if(prL >= prR) return;
    int tmp1 = pre[prL + 1];
    int tmp2 = pos[poR - 1];
    if(tmp1 != tmp2){
        dfs(mp1[tmp1], mp1[tmp2] - 1, poL, mp2[tmp1]);
        dfs(mp1[tmp2], prR, mp2[tmp1] + 1, poR - 1);
    }
    else{
        ++cnt;
        dfs(prL + 1, prR, poL, poR - 1);
    }
}
void solve(int n, int k){//將最終的結果每隔9位數存在ans數組中
    int len = 1;
    ans[1] = 1;
    while(k--){
        for(int i = 1; i <= len; ++i){
            ans[i] *= n;
        }
        for(int i = 1; i <= len; ++i){
            ans[i + 1] += ans[i] / MOD;
            ans[i] %= MOD;
        }
        if(ans[len + 1]) ++len;
    }
    for(int i = len; i >= 1; --i){
        if(i == len) printf("%d", ans[i]);
        else printf("%09d", ans[i]);
    }
    printf("\n");
}
int main(){
    int N;
    scanf("%d", &N);
    for(int i = 0; i < N; ++i){
        scanf("%d", &pre[i]);
        mp1[pre[i]] = i;
    }
    for(int i = 0; i < N; ++i){
        scanf("%d", &pos[i]);
        mp2[pos[i]] = i;
    }
    dfs(0, N - 1, 0, N - 1);
    solve(2, cnt);//計算2的cnt次方,不取模
    return 0;
}
相關文章
相關標籤/搜索