【7004】二叉树的遍历问题
Time Limit: 10 second
Memory Limit: 2 MB
问题描述
输入一棵二叉树的先序和中序遍历序列,输出其后序遍历序列。
Input
输入文件共两行,第一行一个字符串,表示树的先序遍历,第二行一个字符串,表示树的中序遍历。树的结点一律用小写字母表示。
Output
输出文件仅一行,表示树的后序遍历的序列。
Sample Input
abdec dbeac
Sample Output
debca
【题解】
先序遍历。
是先输出当前访问到的节点。
然后访问左儿子。然后访问右儿子。
这也就是说先序遍历的第一个节点肯定是根节点。
然后中序遍历。是先访问左儿子。然后输出访问的节点。然后输出右儿子。
我们可以先根据先序遍历。找到这个树的根节点。
假设根节点root在中序遍历中的位置为pos.
则1..pos-1为根的左子树。
pos+1..max为根的右子树。
然后1..pos-1这个左子树。它的根节点是什么呢?
当然就是先序遍历的第二个节点。
因为先序遍历是先访问了根节点。且先输出根节点。
然后访问根节点的左子树。当然第一个访问的是左子树的根节点。然后输出这个左子树的根节点。然后。。
对!就在第二个节点。它就是我们需要的左子树的根节点。
然后我们依然用中序遍历。找到这个<左子树的根节点>的左子树和右子树。
依次类推。根节点的左子树的左子树的根节点为先序遍历的第3个节点..
这些子树可以用区间先表示出来。
如果区间的大小{上限减去下限为1}则这个节点为最下面一层的节点。叶子节点。那么就不要继续操作了。
然后每层递归(什么?你还看不出来这里要用递归??)都要返回当前这段区间的根节点。给这个根节点
的爸爸。
然后根据得到的l[]和r[]数组(表示某个节点的左儿子和右儿子)。从根节点开始进行后序遍历。
(后序遍历:先访问左儿子。后访问右儿子。最后输出当前访问的这个节点);
【代码】
#include <cstdio> #include <iostream> #include <string> using namespace std; string s1, s2; int tot,ll[29],rr[29],root; int xianxu[29], zhongxu[29]; int now = 1; void input_data() //输入有这么多行。是为了在字符串前面加一个空格。 { //因为C++的字符串从0开始计数。有点不习惯。然后把字母转换成相应的数字。a-z对应1..26 string temp; getline(cin, temp); s1 = " "; s1 += temp; getline(cin, temp); s2 = " "; s2 += temp; for (int i = 1; i <= s1.size() - 1; i++) //字符转数字。 xianxu[i] = s1[i] - 'a' + 1; xianxu[0] = s1.size() - 1; for (int i = 1; i <= s2.size() - 1; i++) zhongxu[i] = s2[i] - 'a' + 1; zhongxu[0] = s2.size() - 1; } int sear_ch(int l, int r) //返回l..r这段区间的根节点。 { if (r < l) //如果出现右界小于左界的情况。则返回0.表示这个节点不存在。 return 0; if (l == r)//如果左界和右界相同。则说明这里只有一个节点。则返回这个节点。 return xianxu[now++];//我们要靠先序来判断l..r这个子树的根节点 else//对于只有一个元素来说。我们认为这个xianxu[now]是一个根节点。 { int pp; int key2 = xianxu[now];//这是l..r这个子树的根节点 for (int i = l; i <= r; i++)//找到根节点在中序中的位置pp if (zhongxu[i] == key2) //中序遍历中L..pp-1,和pp+1.。R分别为key2的左子树和右子树。 { pp = i; break; } now++;//寻找先序遍历中出现的下一个元素即该根节点key2的左子树的根节点。 ll[key2] = sear_ch(l, pp - 1); //注意我们每一段区间的根节点都有记录下来(key2)。然后返回即可。 rr[key2] = sear_ch(pp + 1, r); //先序是先访问完左子树再访问右子树的。要遵循其规律。 return key2;//返回l..r这个区间的根节点。 } } void output_ans(int t) //这是后序遍历一棵树的递归程序。 { if (ll[t] != 0) output_ans(ll[t]); if (rr[t] != 0) output_ans(rr[t]); char aa = t + 'a' - 1;//要输出的是字母; putchar(aa);//输出单个字符。 } void get_ans() { int root = xianxu[now];//先找到整棵树的根节点。 int pos = 0; for (int i = 1;i <= zhongxu[0];i++) //找到其在中序遍历中的位置 if (zhongxu[i] == root) { pos = i; break; } now++;//接下来xianxu[now]指向根节点的左子树的根节点。 ll[root] = sear_ch(1, pos - 1);//这是其左子树 sear_ch(l,r)函数会返回l..r这段区间的根节点。 rr[root] = sear_ch(pos + 1, xianxu[0]);//这是其右子树。 output_ans(root); } int main() { input_data(); get_ans(); return 0; }