1. 程式人生 > >SDUTOJ1291資料結構上機測試4.1:二叉樹的遍歷與應用1

SDUTOJ1291資料結構上機測試4.1:二叉樹的遍歷與應用1

以SDUTOJ1291資料結構上機測試4.1:二叉樹的遍歷與應用1為例

https://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Contest/contestproblem/cid/2711/pid/1291

思路:

遞迴實現,化解子問題解決。

先序:ABDCEF

中序:BDAECF

第一步:根據先序遍歷的特點,我們可以簡單地知道根節點為A

第二步:觀察中序,其中root節點A左側的BD必然是root的左子樹,A右側的ECF必定是root的右子樹

第三步:觀察左子樹BD,左子樹中的根節點必定是大樹的leftchild。在先序中大樹的leftchild位於root之後,所以左子樹的根節點是B。

第四步:同理,root的右子樹的節點ECF中的根節點也可以通過前序遍歷得到。root的右子樹節點ECF中的根節點也可以通過前序遍歷求得。在前序遍歷中,一定是先把root和root的所有左子樹節點遍歷完之後才會遍歷右子樹,並且遍歷的左子樹的第一個節點就是左子樹的根節點。同理,遍歷的右子樹的第一個節點就是右子樹的根節點。

第五步,觀察發現,上面的過程是遞迴的。先找到當前樹的根節點,然後劃分為左子樹,右子樹,然後進入左子樹重複上面的過程,然後進入右子樹重複上面的過程。最後就可以還原一棵樹了。該步遞迴的過程可以簡潔表達如下:

1 確定根,確定左子樹,確定右子樹。

2 在左子樹中遞迴。

3 在右子樹中遞迴。

4 列印當前根。

程式碼實現

#include <bits/stdc++.h>
using namespace std;
void make(int len, char *s1, char *s2, char *s) // s1為先序 s2為中序
{
    int i;
    if (len <= 0)
        return; // return 必不可少 否則死迴圈
    else
    {
        for (i = 0; i < len; i++)
        {
            if (s1[0] == s2[i]) // 在中序中搜索根節點 實現遞迴
                break;
        }
    }
    // 關鍵部分
    make(i, s1 + 1, s2, s);                           // 搜尋上次搜尋左側部分
    make(len - i - 1, s1 + i + 1, s2 + i + 1, s + i); // 搜尋上次搜尋右側部分
    s[len - 1] = s1[0];                               // 後序輸出 把遞迴找出的根節點從後存入 也就是列印當前根
}
int main()
{
    char s1[100], s2[100], s[100];
    scanf("%s %s", s1, s2);
    int len = strlen(s1);
    // s[len] = '\0'; // 不要忘記封口
    make(len, s1, s2, s);
    s[len] = '\0'; // 不要忘記封口
    cout << s << endl;
    return 0;
}