7-4 Structure of a Binary Tree

本文介绍如何通过中序和后序遍历序列构造二叉树,以及如何验证关于二叉树结构的各种陈述,包括节点关系、层次深度和是否为满二叉树。文章详细解释了使用结构体表示节点属性的方法,以及处理字符串输入的具体实现。

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

题目描述

Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder and inorder traversal sequences, a binary tree can be uniquely determined.

Now given a sequence of statements about the structure of the resulting tree, you are supposed to tell if they are correct or not. A statment is one of the following:

A is the root
A and B are siblings
A is the parent of B
A is the left child of B
A is the right child of B
A and B are on the same level
It is a full tree
Note:

Two nodes are on the same level, means that they have the same depth.
A full binary tree is a tree in which every node other than the leaves has two children.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (≤30), the total number of nodes in the binary tree. The second line gives the postorder sequence and the third line gives the inorder sequence. All the numbers in a line are no more than 10^​3 and are separated by a space.

Then another positive integer M (≤30) is given, followed by M lines of statements. It is guaranteed that both A and B in the statements are in the tree.

Output Specification:

For each statement, print in a line Yes if it is correct, or No if not.

Sample Input:

9
16 7 11 32 28 2 23 8 15
16 23 7 32 11 2 28 15 8
7
15 is the root
8 and 2 are siblings
32 is the parent of 11
23 is the left child of 16
28 is the right child of 2
7 and 11 are on the same level
It is a full tree

Sample Output:

Yes
No
Yes
No
Yes
Yes
Yes

题目分析

关键在于由中序和后序序列构造二叉树。这一点在PAT考试中出现过若干次,也是基本功,不会的同学要补习完再继续做题噢。
题目给了不同的陈述。

①15 is the root
②8 and 2 are siblings
③32 is the parent of 11
④23 is the left child of 16
⑤28 is the right child of 2
⑥7 and 11 are on the same level
⑦It is a full tree

因此任务包含

找出二叉树的根(这个只要知道后序序列就能立即确定,简单)
判断是否为兄弟,也就是判断他们的爸爸一样不一样
③也是找节点的父亲
④⑤找孩子
⑥判断两个节点的层次是否相同
⑦判断是否为满二叉树,也就是除了叶子节点外所有的节点的度都为2,这要与完全二叉树区分开来。满二叉树的定义题目中也很友善的告诉了我们,所以读题一定要仔细啊朋友们。

总得来说,需要我们拿到一个节点的值,就能快速获得节点的相关属性。包括父亲左右孩子层次(深度)。
因此我们可以将节点用以下的结构体表示,并声明node类型的数组,数组的下标即对应节点的值。

// 记录左右孩子、父亲结点的编号、层次 
struct node{
	int lchild = -1,rchild = -1;
	int father,level; 
};
node tree[1010];//下标即对应结点的值。可由值快速获取到结点的信息

万事具备,只剩处理字符串的输入了。这里提供两个方案
首先利用 getline(cin,s) 读入一行带有空格的字符串。

方案一,利用stringstream按空格切割字符串

stringstream可以方便的进行数据类型转换,其实还有一个妙用就是按空格分割字符串。
想知道具体代码的可参考这篇博客,这里不做展开。

方案二,利用sscanf函数

C 库函数 int sscanf(const char *str, const char *format, …) 从字符串读取格式化输入。

也就是先利用getline读入一整行的字符串,接着判断字符串中是包含“root”、“siblings”、“full"进而确定字符串是哪一个询问的语句,接着利用sscanf提取其中的数字,再进行判断即可。
具体可参考这篇博文

代码

PAT题库中没有这一题,因此并不能确保以下的代码是完全正确的,有问题欢迎留言。

#include <bits/stdc++.h>
using namespace std;

//数的每一个结点 
// 记录左右孩子、父亲结点的编号、层次 
struct node{
	int lchild = -1,rchild = -1;
	int father,level; 
};

node tree[1010];//下标即对应结点的值。可由值快速获取到结点的信息

vector<int>post,in;
map<int,int> pos;//快速找到某点在中序遍历的下标 
bool flag = true;//孩子的个数

void build(int &r,int inL,int inR,int postL,int postR,int father,int level){
	//根、中序遍历的起始坐标、后序遍历的起始坐标、父亲结点、层次
	if(inL > inR)return;
	r = post[postR];//获取目前根的值
	int i = pos[r]; //找到位置 
//	cout<<i<<"\t"<<r<<endl;
	tree[r].father = father;
	tree[r].level = level;
	
	int cnt = 0;
	if(inL < i){
		//存在左孩子
		build(tree[r].lchild,inL,i-1,postL,postL+(i-inL-1),r,level+1);
		cnt++; 
	}
	if(i < inR){
		//存在右孩子
		build(tree[r].rchild,i+1,inR,postL+(i-inL),postR-1,r,level+1);
		cnt++; 
	}
	if(cnt == 1){//不能用cnt !=2 这个条件判断。因为叶子节点的孩子个数为0 
	//	cout<<"cnt = "<<cnt<<endl;
		flag = false;//不是满二叉树
	}
	 
}
int main(){
	int n,m;
	scanf("%d",&n);
	in.resize(n+1);post.resize(n+1);
	for(int i=1;i<=n;i++) cin>>post[i];
	for(int i=1;i<=n;i++){
		cin>>in[i];
		pos[in[i]] = i;//记录节点值在中序遍历中的下标位置 
	}
	
	int root;
	build(root,1,n,1,n,-1,1);
	
//	for(int i=1;i<= n;i++){
//		int t = in[i];
//		cout<<t<<"\t"<<tree[t].father<<'\t'<<tree[t].level<<'\t'<<tree[t].lchild<<"\t"<<tree[t].rchild<<endl;
//	}
//	cout<<"root = "<<root<<endl;
	cin>>m;
	getchar();
	while(m--){
		string s;
		getline(cin,s);//一行读入 
	//	cout<<"s = "<<s<<endl;
		if(s.find("root") != string::npos){//含有root 
			int num;
			sscanf(s.c_str(), "%d is the root", &num);
			num == root ? printf("Yes\n"):printf("No\n");
		} 
		else if(s.find("siblings") != string::npos){//是否为兄弟节点 -》父节点是否相同 
	        int a, b;
	        sscanf(s.c_str(), "%d and %d are siblings", &a, &b);
	        tree[a].father == tree[b].father ? printf("Yes\n") : printf("No\n");
	    }
	    else if(s.find("parent") != string::npos){
	        int a, b;
	        sscanf(s.c_str(), "%d is the parent of %d", &a, &b);
	        a == tree[b].father ? printf("Yes\n") : printf("No\n");
	    }
	    else if(s.find("left child") != string::npos){
	        int a, b;
	        sscanf(s.c_str(), "%d is the left child of %d", &a, &b);
	        a == tree[b].lchild ? printf("Yes\n") : printf("No\n");
	    }
	    else if(s.find("right child") != string::npos){
	        int a, b;
	        sscanf(s.c_str(), "%d is the right child of %d", &a, &b);
	        a == tree[b].rchild ? printf("Yes\n") : printf("No\n");
	    }
	    else if(s.find("level") != string::npos){
	        int a, b;
	        sscanf(s.c_str(), "%d and %d are on the same level", &a, &b);
	        tree[a].level == tree[b].level ? printf("Yes\n") : printf("No\n");
	    }
	    else if(s.find("full") != string::npos){
	        flag ? printf("Yes\n") : printf("No\n");
	    }
	}
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值