19年春季第四题 PAT甲级 1159 Structure of a Binary Tree(30分)

110 篇文章 0 订阅

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

做了好久,看到中序和后序直接动态建树了,后面发现动态建树就是sb,因为后面需要靠值来找到这个结点。最后用了静态建树,中后也可以静态建树的,静态建树的话节点里面的左右子树存的都是下标值,我们这里用val直接当下标值,记得先将左右子树的设为-1,然后build函数返回值是int。
静态建完树就简单很多了,七种问题,是否为根结点,是否为兄弟,是否是父亲,是否是左孩子,是否是右孩子,是否同一层,是否是full二叉树,这个full二叉树真的要好好看题,什么鬼玩意,除了叶子结点每个结点都有左右子树就是full二叉树
通过bfs给每个结点父亲赋值,层级赋值,就可以做完大部分了。最后一个也在bfs里弄,如果又一个节点只有左or只有右,就让bfs返回一个false。
最后就是怎么获取问题了,

string question[10];
		for(int j = 0;;j++){
			cin>>question[j];
			char c = getchar();
			if(c == '\n') break;
		}

我是这样写的,一开始用while循环,发现不能给每个单词赋值,因为读取到空格,会自动读取下一个字符串,所以弄一个字符串数组来存一句话里的每个单词,如果读到了换行符,就break。
然后就在字符串数组里找对应的单词即可

#include<iostream>//静态建树
#include<unordered_map>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;
struct node{
	int val;
	int father;
	int lchild=-1,rchild=-1;
	int layer;
}tree[1005];

int n;
vector<int> postOrder(n+2);
vector<int> inOrder(n+2);
unordered_map<int,int> ma;

int buildTree(int postL, int postR,int inL, int inR){
	if(postL > postR) return -1;
	int root = postOrder[postR];
	tree[root].val = root;
	tree[root].lchild = tree[root].rchild = -1;
	int leftSubTree = ma[root] - inL;
	tree[root].lchild = buildTree(postL,postL + leftSubTree-1,inL,inL+leftSubTree-1);
	tree[root].rchild = buildTree(postL+leftSubTree,postR-1,inL+leftSubTree+1,inR);
	return root;
}

bool bfs(int s){
	queue<int> q;
	tree[s].layer = 1;
	q.push(s);
	bool flag = true;
	while(!q.empty()){
		int topNode = q.front();
		q.pop();
		bool flag1 = false, flag2 = false;//两个都为false证明都没有 
		if(tree[topNode].lchild != -1){
			tree[tree[topNode].lchild].layer = tree[topNode].layer+1;
			tree[tree[topNode].lchild].father = topNode;
			q.push(tree[topNode].lchild);
			flag1 = true;
		}
		if(tree[topNode].rchild != -1){
			tree[tree[topNode].rchild].layer = tree[topNode].layer+1;
			tree[tree[topNode].rchild].father = topNode;
			q.push(tree[topNode].rchild);
			flag2 = true;
		}
		if((flag1 == false && flag2 ==true) || (flag2 == false && flag1 ==true)) flag = false;
	}
	return flag;
}

int main(){
	cin>>n;
	for(int i = 0; i < n; i++){
		cin>>postOrder[i];
	}
	for(int i = 0; i < n; i++){
		cin>>inOrder[i];
	}
	for(int i = 0; i < n; i++){
		ma[inOrder[i]] = i;
	}
	int root = buildTree(0,n-1,0,n-1);
	bool f = bfs(root);
	int q;
	cin>>q;
	int u,v;
	for(int i = 0; i < n; i++){
		string question[10];
		for(int j = 0;;j++){
			cin>>question[j];
			char c = getchar();
			if(c == '\n') break;
		}
		for(int j = 0; j < 10; j++){
			if(question[j] == "root"){
				u = stoi(question[0]);
				if(root == u) cout<<"Yes\n";
				else cout<<"No\n";
			}
			if(question[j] == "siblings"){//判断是否是兄弟结点,判断父亲是否是同一个,bfs中给父亲结点赋值 
				u = stoi(question[0]);
				v = stoi(question[2]);
				if(tree[u].father == tree[v].father) cout<<"Yes\n";
				cout<<"No\n"; 
			}
			if(question[j] == "parent"){//判断是否是父亲 
				u = stoi(question[0]);
				v = stoi(question[5]);
				if(tree[v].father == u) cout<<"Yes\n";
				else cout<<"No\n";
			}
			if(question[j] == "left"){//判断是否是左孩子 
				u = stoi(question[0]);
				v = stoi(question[6]);
				if(tree[v].lchild == u) cout<<"Yes\n";
				else cout<<"No\n"; 
			}
			if(question[j] == "right"){//判断是否是右孩子 
				u = stoi(question[0]);
				v = stoi(question[6]);
				if(tree[v].rchild == u) cout<<"Yes\n";
				else cout<<"No\n"; 
			}
			if(question[j] == "same"){//是否同一层 
				u = stoi(question[0]);
				v = stoi(question[2]);
				if(tree[u].layer == tree[v].layer) cout<<"Yes\n";
				else cout<<"No\n";
			}
			if(question[j] == "full"){//是否是满二叉树,看倒数第二层的结点是否都有左右孩子 
				if(f) cout<<"Yes\n";
				else cout<<"No\n";
			}
		}
	}
	return 0;
}

要通过值来找结点的话必须静态建树

//用静态建树,将值当做在数组中的下标,这样方便找这个结点
//兄弟就判断是否是同一个父亲,通过bfs给给每个父亲赋值,再给层赋值,再通过bfs判断每个结点是否都有两个子结点
#include<iostream>
#include<vector>
#include<unordered_map>
#include<queue>
using namespace std;
struct node{
	int val;//通过val来找 
	int lchild,rchild;//子结点就是子结点的值,也就是子结点在数组中的下标 
	int father;
	int layer;
}tree[1005]; 

vector<int> postOrder;
vector<int> inOrder;
unordered_map<int,int> ma;
bool flag = true;//如果是full树就是true 

int buildTree(int postL,int postR,int inL,int inR){
	if(postL > postR) return -1;//-1代表空结点
	int root = postOrder[postR];
	tree[root].lchild = tree[root].rchild = -1;
	int subLeftTree = ma[postOrder[postR]] - inL;
	tree[root].lchild = buildTree(postL,postL+subLeftTree-1,inL,inL+subLeftTree-1);
	tree[root].rchild = buildTree(postL+subLeftTree,postR-1,inL+subLeftTree+1,inR);
	return root; 
}

void bfs(int s){
	queue<int> q;
	tree[s].layer = 1;
	q.push(s);
	while(!q.empty()){
		bool haveL = false, haveR = false;
		int topNode = q.front();
		q.pop();
		if(tree[topNode].lchild != -1){
			haveL = true;
			tree[tree[topNode].lchild].father = topNode;
			tree[tree[topNode].lchild].layer = tree[topNode].layer+1;
			q.push(tree[topNode].lchild);
		}
		if(tree[topNode].rchild != -1){
			haveR = true;
			tree[tree[topNode].rchild].father = topNode;
			tree[tree[topNode].rchild].layer = tree[topNode].layer+1;
			q.push(tree[topNode].rchild);
		}
		if((!haveL && haveR) || (!haveR && haveL)){
			flag = false;
		}
	}
}

int main(){
	int n;
	cin>>n;
	postOrder.resize(n+1);
	inOrder.resize(n+1);
	for(int i = 0; i < n; i++){
		cin>>postOrder[i];
	}
	for(int i = 0; i < n; i++){
		cin>>inOrder[i];
	}
	for(int i = 0; i < n; i++){
		ma[inOrder[i]] = i;
	}
	int root = buildTree(0,n-1,0,n-1);
	bfs(root);
	string s[10];
	int q;
	cin>>q;
	int u,v;
	for(int i = 0; i < q; i++){
		for(int j = 0; ;j++){
			cin>>s[j];
			char c = getchar();
			if(c =='\n') break;
		}
		for(int j = 0; j < 10; j++){
			if(s[j] == "root"){
				u = stoi(s[0]);
				if(root == u) cout<<"Yes\n";
				else cout<<"No\n";
				break;
			}
			if(s[j] == "siblings"){
				u = stoi(s[0]);
				v = stoi(s[2]);
				if(tree[u].father == tree[v].father) cout<<"Yes\n";
				else cout<<"No\n";
				break;
			}
			if(s[j] == "parent"){
				u = stoi(s[0]);
				v = stoi(s[5]);
				if(tree[v].father == u) cout<<"Yes\n";
				else cout<<"No\n";
				break;
			}
			if(s[j] == "left"){
				u = stoi(s[0]);
				v = stoi(s[6]);
				if(tree[v].lchild == u) cout<<"Yes\n";
				else cout<<"No\n";
				break;
			}
			if(s[j] == "right"){
				u = stoi(s[0]);
				v = stoi(s[6]);
				if(tree[v].rchild == u) cout<<"Yes\n";
				else cout<<"No\n";
				break;
			}
			if(s[j] == "same"){
				u = stoi(s[0]);
				v = stoi(s[2]);
				if(tree[u].layer == tree[v].layer) cout<<"Yes\n";
				else cout<<"No\n";
				break;
			}
			if(s[j] == "full"){
				if(flag) cout<<"Yes\n";
				else cout<<"No\n";
				break;
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值