二叉树-先序+中序还原二叉树,输出后序遍历序列 C++代码实现
这里洛谷的题目提交不了,于是在山东理工大学的ACMOJ上找到了一个类似的题目,不过不是让输出后续遍历的结果,而是输出二叉树的深度。
其实我们把二叉树已经构造好的前提下,输出深度或者后序其实都很easy!
思路:
(可能说的不清楚,你可以根据题目给的前序和中序样例进行手算)
1、题目中已经给出了前序和中序遍历的结果,分别定义为a和b
根左右 左根右
2、我们先看前序遍历的结果字符串a,第一个字符一定是根节点。
同时在中序列字符串b中找到根节点的下标,那么在这个下标的左边,一定都是
左子树,而右边直至b末尾的字符一定都是右子树(因为中序遍历为 左-根-右)
3、那么这里我们可以将a进行划分成两个片段
从根节点往后数k个(这里的k大小=根节点在b中的下标),这是第一个片段,和b中根节点的左边【对应】
然后其余的直至末尾是第二个片段,和b中根节点的右边【对应】
4、那么新形成的两对字符一一对应,进行递归处理。
5、下面有一个很重要的点:
现在,我们已经把a和b分别划分成了两个片段,
记作A[1],A[2];B[1],B[2] (注意这里的A[1]是不包括根节点的)
那么根节点的子节点,一定是a新划分的第一个片段的第一个字符,即A[1][0]
(这个性质你可以多画几个样例试一下)
那么我们如何判断把A[1][0]是赋值给根节点的左子树还是右子树呢?
这里我在递归函数中传递了一个参数op,如果是1说明是左子树;如果是2,说明是右子树。那么在每次进入递归函数的时候,可以根据
根节点,即char ch
参数op,即int op ,进行建树
然后在递归函数中进行递归。同时需要注意的另外一个点是:如果在b中找到跟节点的下标在最左边,即下标为0,那么说明不用让左进行建树了,因为根据中序遍历 左-根-右
左边没有字符,说明没有了左子树;如果在b中找到跟节点的下标在最右边,说明没有了右子树(这个在代码中有体现)
总之,自己多找几个样例试一下,发现其中的几个小细节的规律!
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define sf(x) scanf("%d", &x);
#define de(x) cout << x << " ";
#define Pu puts("");
string a, b;
struct E {
int l, r;
} e[75];
void fun(string a, string b, char ch, int op) {
if (op == 1)
e[ch - 'A'].l = a[0] - 'A';
else if (op == 2)
e[ch - 'A'].r = a[0] - 'A';
int t = b.find(a[0]);
if (t != 0) { // 左
fun(a.substr(1, t), b.substr(0, t), a[0], 1);
}
if (t != b.size() - 1) { // 右
fun(a.substr(t + 1), b.substr(t + 1), a[0], 2);
}
}
int getDep(int x) { // 得到深度
if (x == -1)
return 0;
if (e[x].l == -1 && e[x].r == -1)
return 0;
return max(getDep(e[x].l), getDep(e[x].r)) + 1;
}
int main() {
int T;
while (cin >> T) {
cin >> a >> b;
for (int i = 0; i < 70; i++) {
e[i].l = e[i].r = -1; // 初始化,便于后序遍历输出
}
int t = b.find(a[0]);
if (t != 0) { // 左
fun(a.substr(1, t), b.substr(0, t), a[0], 1);
}
if (t != b.size() - 1) { // 右
fun(a.substr(t + 1), b.substr(t + 1), a[0], 2);
}
de(getDep(a[0] - 'A') + 1);
Pu;
}
return 0;
}
更多推荐
所有评论(0)