题目描述
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;
}