1. 程式人生 > >POJ 2255 -- Tree Recovery

POJ 2255 -- Tree Recovery

思路 node 空字符 ble 字符 == 二叉樹遍歷 tab body

Tree Recovery
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 16032 Accepted: 9865

題意:

根據二叉樹的先序遍歷和中序遍歷,求後序遍歷。

解題思路:

1)遞歸(不建樹)

可以先按照用筆和紙的形式去推導出後序序列。推導過程省略,在推導過程中我們會發現規律:

假設 前序序列是 A B E H F C G I

中序序列是 H E B F A C I G (圖如下)

技術分享圖片

每一次從前序序列裏,按順序抽取出字母就能將中序序列分割,並根據中序遍歷的特性。分割後的兩部分分別是 左子樹 和 右子樹(註意,他們也是二叉樹!)

就像這樣:取A, 中序序列被分割為 左子樹:H E B F 右子樹 C I G

繼續取B,但是這次是對左子樹:H E B F 進行分割。 分割結果是: 左子樹:H E 右子樹 B F

直到不能再分割,遞歸會返回去到第一次使用 A 分割出來的 右子樹 裏繼續分割

上述整個過程都是遞歸,所以結合代碼和用紙筆畫一次會更好理解

char *strchr(const char* _Str,char _Val) 頭文件:#include <string.h> 功能:查找字符串_Str中首次出現字符_Val的位置 說明:返回首次出現_Val的位置的指針,返回的地址是被查找字符串指針開始的第一個與Val相同字符的指針,如果Str中不存在Val則返回NULL
返回值:成功則返回要查找字符第一次出現的位置,失敗返回NULL
 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 const int maxn = 30;
 5 
 6 
 7 void Build(char *a,char *b,char *s,int n)
 8 {//a是先序遍歷,b是中序遍歷
 9     if(n<=0)
10         return;
11     else{
12         ///記錄根節點在中序遍歷中的位置
13         int k = strchr(b,a[0
]) - b; 14 ///0~k-1為左子樹 15 Build(a+1,b,s,k); 16 ///k+1~n為右子樹 17 Build(a+k+1,b+k+1,s+k,n-k-1); 18 s[n-1] = a[0]; 19 } 20 } 21 22 int main() 23 { 24 char a[maxn],b[maxn]; 25 while(cin>>a>>b) 26 { 27 char ans[maxn]; 28 int len = strlen(b); 29 Build(a,b,ans,len); 30 ans[len] = 0;///加結束符 31 cout<<ans<<endl; 32 } 33 return 0; 34 }

技術分享圖片

2)二叉樹遍歷(建樹)

對二叉樹的 前序遍歷、中序遍歷、後序遍歷 均可以使用DFS來做,
均是自上而下、自左至右遍歷,區別在於打印節點的時機不同:
[前序遍歷] 從父節點進入時打印當前節點
[中序遍歷] 從左子樹返回時打印當前節點
[後序遍歷] 從右子樹返回時打印當前節點

 1 #include<iostream>
 2 #include<cstring>
 3 #include<string>
 4 
 5 using namespace std;
 6 const int STR_LEN = 27;//樹遍歷序列最大長度
 7 const int NULL_CHAR = \0;//空字符
 8 
 9 ///結點結構
10 class Node{
11 public:
12     char name;//節點名稱
13     Node *left;//左子樹根節點
14     Node *right;//右子樹根節點
15     Node():name(NULL_CHAR),left(NULL),right(NULL){}//初始化
16     ~Node()
17     {
18         name = NULL_CHAR;
19         delete left;left = NULL;
20         delete right;right = NULL;
21     }
22 };
23 
24 Node* createTree(char *pro,char *in,int n)
25 {
26     Node *root = new Node;
27     if(n <= 0)
28     {
29         return root;
30     }else{
31         int k = strchr(in,pro[0]) - in;//找到根節點在中序遍歷中的位置
32         root->name = pro[0];
33         root->left = createTree(pro+1,in,k);
34         root->right = createTree(pro+k+1,in+k+1,n-k-1);
35         return root;
36     }
37 }
38 
39 void dfs(Node *root,char *output)
40 {
41     if(root == NULL)
42     {
43         return;
44     }
45     dfs(root->left,output);
46     dfs(root->right,output);
47     ///構造後序序列,從右子樹返回時把當前的結點放到序列末尾
48     output[strlen(output)] = root->name;
49     //或寫成:
50     //*(output+strlen(output)) = root->name;
51 }
52 
53 int main()
54 {
55     char pro[STR_LEN],in[STR_LEN];
56     while(cin>>pro>>in)
57     {
58         int len = strlen(in);
59         Node *root = createTree(pro,in,len);
60         char output[STR_LEN] = {NULL_CHAR};///一定要初始化為空
61         dfs(root,output);
62         output[len] = 0;
63         cout<<output<<endl;
64         delete root;
65     }
66     return 0;
67 }

技術分享圖片


POJ 2255 -- Tree Recovery