1119 Pre- and Post-order Traversals (30 分)

博客围绕PAT1119题目,探讨根据二叉树先序和后序遍历重构二叉树及判断其唯一性。指出判断树是否唯一关键看节点孩子是否都存在,除叶子节点外其他节点左右孩子都在则唯一。还介绍了根据先序后序重建二叉树的方法,并给出代码判断思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PAT1119
点击查看题目
题意给出二叉树的先序遍历与后序遍历,要求判断据两序列重构的二叉树是否唯一。
唯一输出Yes并且输出中序遍历,不唯一输出No,然后输出任意中序遍历。

这个题我想了好半天可能太笨了吧,之前写过先序加中序,还有后序加中序,那些都是在书上看的题解然后自己写的,这个自己想了一会觉得还是很有意思的。

先说怎么根据先序还有后序重建二叉树我是每次都把后序的最后一个元素当根来写的,后序的最后一个元素当作根,后序的倒数第二个元素只有两种情况:
1.后序最后一个元素的右孩子。
2.是后序结点的左孩子。

注意都是孩子,不是子树,而且题目说能不能构建出唯一的树,那么说明有些情况是可以确定左右孩子的,能确定的时候就可以构造出正确的,不能确定的时候就构造出不确定的。
那么什么时候确定呢?
我观察发现 当先序序列与后序序列缩短到2时根的左右孩子时不能确定的。
比如:
先序:1 , 2
后序:2, 1
2是不是可以当左子孩子,也可以当右孩子? 为什么会不能确定呢? 应为1少了一个孩子,它不是所有孩子都建在,先序是根左右,后序是左右根。试想如果少了一个孩子。则 先序是左根,后序是根左, 还是 先序是右根, 后序是根右,谁能确定?? 但是如果孩子没有少, 应为先序遍历的性质,
左孩子后面一定是右孩子,右孩子后面一定是根。左右之分就出来了。
可以模拟一下 先序 1 2 3 后序 2 3 1,就能想到。

总结一下,判断重建的树是不是唯一其实就是看这个树的节点的孩子是否都建在,即除了叶子结点没孩子,其他结点的左右孩子都在。

根据后序还有先序怎么重建二叉树:
把后序最后一个当作根, 然后在先序里面查找后序倒数(postR - 1)第二个对应的下标,postR-1这个数前面也说了一定是左右孩子其中的一个,所有直接当作右孩子就行了,因为是左是还是右无所谓,打个比方如果真的是右!好我们建树对了,然后再判断是否唯一就行,如果不是右孩子,无所谓啊,因为如果答案唯一,这个孩子就应该是右孩子,既然不是右孩子,我们判断的时候就会判断出答案不唯一,反正不影响。
扯远了,在先序里面查找postR-1对应的下标,因postR-1是根的右孩子,则对应到先序中应当是根左右 右部分对应的第一个元素,哈哈哈,想到这里文就茅塞顿开啊!这样不就确定了,该根左右子树对应的先序还有后序序列了吗???然后递归下去,直到没有元素可以划分为止。想到这里在实现的时候就很类似与知道先序后者后序,与中序求数的题目了。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 31;
int pre[N];
int post[N];
int nums = 0;
struct node {
    int data;
    node *lchild, *rchild;
};
node* newNode(int x) {
    node* Node = new node;
    Node->data = x;
    Node->lchild = Node->rchild = NULL;
    return Node;
}
node* rebuild(int prel, int prer, int pol, int por) {
    if(pol > por) return NULL;            //这里为啥会有两个判断? 一个pro - pol 一个 pol > por ? 
    node* root = newNode(post[por]); // 用 per 1 2 3 posr 3 2 1 , pre 1 2  3 post 2 3 1模拟即可。
    if(por - pol == 0) return root; 
    int k = prel;
    for(; k <= prer; k++) {
        if(pre[k] == post[por-1]) break;
    }
    int Leftnums = k- prel - 1; // post 左子树的个数
    root->lchild =  rebuild(prel+1, k-1, pol, pol + Leftnums - 1);
    root->rchild =  rebuild(k, prer, pol + Leftnums, por - 1);
    return root;
}
void inorder(node* root, int n) { //中序遍历
    if(root == NULL) return;
    inorder(root->lchild, n);
    printf("%d", root->data);
    nums++;
    if(nums < n) printf(" ");
    else printf("\n");
    inorder(root->rchild, n);
}
bool judge(node* root) {
	if(root == NULL) return true;
	if(root->lchild != NULL && root->rchild ==NULL || root->rchild 
	!= NULL && root->lchild ==NULL) return false; //判错因子
	return judge(root->lchild) && judge(root->rchild);
	
}
int main() {
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i++) scanf("%d", &pre[i]);
    for(int i = 0; i < n; i++) scanf("%d", &post[i]);
    node* root = rebuild(0,n-1, 0, n-1);
    if(judge(root)) printf("Yes\n");
    else printf("No\n");
    inorder(root, n);
    return 0;
}

我为了证实我的推论,就是当先序与后序长度为2时生成的二叉树不唯一,我直接就用这个来判断是否时唯一的二叉树了。即在重构的时候判断是否有一层dfs里面 先序后序的长度为2? 有直接令全局变量为true, 我认为长度为2的先序后序序列的出现直接就导致该树构造不唯一,我把代码中判错的judge用上述方法替代了,通过此题。
总结,据先序后序重构时,不出现先序后序长度为2的情况,此树唯一!

#include<bits/stdc++.h>
using namespace std;
const int N = 31;
int pre[N];
int post[N];
int nums = 0;
bool flag = false;
struct node {
    int data;
    node *lchild, *rchild;
};
node* newNode(int x) {
    node* Node = new node;
    Node->data = x;
    Node->lchild = Node->rchild = NULL;
    return Node;
}
node* rebuild(int prel, int prer, int pol, int por) {
	if(por - pol + 1 == 2 && prer - prel + 1 == 2) flag = true; //有长度为2的先序后序就判不唯一! 
    if(pol > por) return NULL;
    node* root = newNode(post[por]);
    if(por - pol == 0) return root; 
    int k = prel;
    for(; k <= prer; k++) {
        if(pre[k] == post[por-1]) break;
    }
    int Leftnums = k- prel - 1;
    root->lchild =  rebuild(prel+1, k-1, pol, pol + Leftnums - 1);
    root->rchild =  rebuild(k, prer, pol + Leftnums, por - 1);
    return root;
}
void inorder(node* root, int n) {
    if(root == NULL) return;
    inorder(root->lchild, n);
    printf("%d", root->data);
    nums++;
    if(nums < n) printf(" ");
    else printf("\n");
    inorder(root->rchild, n);
}
//bool judge(node* root) {
//	if(root == NULL) return true;
//	if(root->lchild != NULL && root->rchild ==NULL || root->rchild != NULL && root->lchild ==NULL) return false;
//	return judge(root->lchild) && judge(root->rchild);
//	
//}
int main() {
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i++) scanf("%d", &pre[i]);
    for(int i = 0; i < n; i++) scanf("%d", &post[i]);
    node* root = rebuild(0,n-1, 0, n-1);
    if(!flag) printf("Yes\n"); //全局代替了判错函数judge 
    else printf("No\n");
    inorder(root, n);
    return 0;
}
1. 用户与身体信息管理模块 用户信息管理: 注册登录:支持手机号 / 邮箱注册,密码加密存储,提供第三方快捷登录(模拟) 个人资料:记录基本信息(姓名、年龄、性别、身高、体重、职业) 健康目标:用户设置目标(如 “减重 5kg”“增肌”“维持健康”)及期望周期 身体状态跟踪: 体重记录:定期录入体重数据,生成体重变化曲线(折线图) 身体指标:记录 BMI(自动计算)、体脂率(可选)、基础代谢率(根据身高体重估算) 健康状况:用户可填写特殊情况(如糖尿病、过敏食物、素食偏好),系统据此调整推荐 2. 膳食记录与食物数据库模块 食物数据库: 基础信息:包含常见食物(如米饭、鸡蛋、牛肉)的名称、类别(主食 / 肉类 / 蔬菜等)、每份重量 营养成:记录每 100g 食物的热量(kcal)、蛋白质、脂肪、碳水化合物、维生素、矿物质含量 数据库维护:管理员可添加新食物、更新营养数据,支持按名称 / 类别检索 膳食记录功能: 快速记录:用户选择食物、输入食用量(克 / 份),系统自动计算摄入的营养成 餐次类:按早餐 / 午餐 / 晚餐 / 加餐类记录,支持上传餐食照片(可选) 批量操作:提供常见套餐模板(如 “三明治 + 牛奶”),一键添加到记录 历史记录:按日期查看过往膳食记录,支持编辑 / 删除错误记录 3. 营养析模块 每日营养摄入析: 核心指标计算:统计当日摄入的总热量、蛋白质 / 脂肪 / 碳水化合物占比(按每日推荐量对比) 微量营养素析:检查维生素(如维生素 C、钙、铁)的摄入是否达标 平衡评估:生成 “营养平衡度” 评(0-100 ),指出摄入过剩或不足的营养素 趋势析: 周 / 月营养趋势:用折线图展示近 7 天 / 30 天的热量、三大营养素摄入变化 对比析:将实际摄入与推荐量对比(如 “蛋白质摄入仅达到推荐量的 70%”) 目标达成率:针对健
American Heritage 题目描述 Farmer John takes the heritage of his cows very seriously. He is not, however, a truly fine bookkeeper. He keeps his cow genealogies as binary trees and, instead of writing them in graphic form, he records them in the more linear tree in-order" and tree pre-order" notations. Your job is to create the `tree post-order" notation of a cow"s heritage after being given the in-order and pre-order notations. Each cow name is encoded as a unique letter. (You may already know that you can frequently reconstruct a tree from any two of the ordered traversals.) Obviously, the trees will have no more than 26 nodes. Here is a graphical representation of the tree used in the sample input and output: C / \ / \ B G / \ / A D H / \ E F The in-order traversal of this tree prints the left sub-tree, the root, and the right sub-tree. The pre-order traversal of this tree prints the root, the left sub-tree, and the right sub-tree. The post-order traversal of this tree print the left sub-tree, the right sub-tree, and the root. ---------------------------------------------------------------------------------------------------------------------------- 题目大意: 给出一棵二叉树的中序遍历 (inorder) 和前序遍历 (preorder),求它的后序遍历 (postorder)。 输入描述 Line 1: The in-order representation of a tree. Line 2: The pre-o rder representation of that same tree. Only uppercase letter A-Z will appear in the input. You will get at least 1 and at most 26 nodes in the tree. 输出描述 A single line with the post-order representation of the tree. 样例输入 Copy to Clipboard ABEDFCHG CBADEFGH 样例输出 Copy to Clipboard AEFDBHGC c语言,代码不要有注释
06-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值