信奥赛CSP-J复赛集训(图和树专题)(7):P1030 [NOIP 2001 普及组] 求先序排列
题目描述
给出一棵二叉树的中序与后序排列。求出它的先序排列。(约定树结点用不同的大写字母表示,且二叉树的节点个数 $ \le 8$)。
输入格式
共两行,均为大写字母组成的字符串,表示一棵二叉树的中序与后序排列。
输出格式
共一行一个字符串,表示一棵二叉树的先序。
输入输出样例 #1
输入 #1
BADC
BDCA
输出 #1
ABCD
说明/提示
【题目来源】
NOIP 2001 普及组第三题
AC代码
#include<bits/stdc++.h>
using namespace std;
string z, h; // z存储中序排列,h存储后序排列
// 递归函数,用于生成先序排列
// 参数:l1, r1为当前子树后序遍历的起始和结束索引
// l2, r2为当前子树中序遍历的起始和结束索引
void qx(int l1, int r1, int l2, int r2) {
char root = h[r1]; // 后序排列的最后一个字符是当前子树的根节点
cout << root; // 输出根节点(先序遍历的顺序)
int mid = z.find(root); // 查找根节点在中序排列中的位置
// 递归处理左子树
if (mid > l2) { // 如果中序中存在左子树
// 左子树的后序排列范围:l1 到 l1 + (mid - l2 - 1)
// 左子树的中序排列范围:l2 到 mid - 1
qx(l1, l1 + (mid - l2) - 1, l2, mid - 1);
}
// 递归处理右子树
if (r2 > mid) { // 如果中序中存在右子树
// 右子树的后序排列范围:l1 + (mid - l2) 到 r1 - 1
// 右子树的中序排列范围:mid + 1 到 r2
qx(l1 + (mid - l2), r1 - 1, mid + 1, r2);
}
}
int main() {
cin >> z >> h; // 输入中序和后序排列字符串
int l1 = 0, r1 = h.size() - 1; // 初始后序排列的整个范围
int l2 = 0, r2 = z.size() - 1; // 初始中序排列的整个范围
qx(l1, r1, l2, r2); // 从根节点开始递归生成先序排列
return 0;
}
功能分析
- 输入处理:程序读取中序排列字符串
z
和后序排列字符串h
。 - 递归函数
qx
:- 确定根节点:每次递归时,后序排列的最后一个字符即为当前子树的根节点。
- 输出根节点:按照先序排列的顺序,首先输出根节点。
- 分割左右子树:利用根节点在中序排列中的位置
mid
,将中序排列分割为左子树和右子树。 - 递归处理子树:
- 左子树:根据中序排列中左子树的范围确定后序排列中对应的左子树范围,并进行递归处理。
- 右子树:同理,确定右子树在后序和中序中的范围,递归处理。
- 递归终止条件:当子树范围不合法时(如左/右子树不存在),递归调用结束。
文末彩蛋:
关注并查看老师的个人主页,学习完整csp信奥赛完整系列课程: https://edu.csdn.net/lecturer/7901