PAT Advanced 1110 Complete Binary Tree (25) [完全⼆叉树]

题目

Given a tree, you are supposed to tell if it is a complete binary tree.
Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (<=20) which is the total number of nodes in the tree — and hence the nodes are numbered from 0 to N-1. Then N lines follow, each corresponds to a node, and gives the indices of the lef and right children of the node. If the child does not exist, a “-” will be put at the position. Any pair of children are separated by a space.
Output Specification:
For each case, print in one line “YES” and the index of the last node if the tree is a complete binary tree, or “NO” and the index of the root if not. There must be exactly one space separating the word and the number.
Sample Input 1:
9
7 8
– –
– –
– –
0 1
2 3
4 5
– –
– –
Sample Output 1:
YES 8
Sample Output 2:
8
– –
4 5
0 6
– –
2 3
– 7
– –
– –
Sample Output 2:
NO 1

题目分析

已知树所有节点的子节点信息,判断是否是完全二叉树,是打印YES+最后一个节点,否打印NO+根节点

解题思路

  1. 深度遍历树,将树中节点存储与数组中,根节点index=0,其左右子节点index分别为2i+1,2i+2
  2. 判断是否为完全二叉树
    2.1 方式一:判断前后节点index是否相差1(若使用数组存储判断数组中有没有浪费的空闲位置,因为完全二叉树使用数组存储时中间没有空闲位置)
    2.2 方式二:最大index==结点数n-1,若相等即为二叉树
    2.3 方式三:BFS借助队列层级遍历树,完全二叉树中间不会遇到NULL

Code

Code 01

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int maxn = 30;
bool isRoot[maxn];  // 结点是否是根结点
struct Node {
    int left, right;    // 左孩子和右孩子的下标
} node[maxn];   // 二叉树结点静态数组
// input函数输入数据
int input() {
    char id[3];
    scanf("%s", id);    // 输入结点编号
    if(id[0] == '-') {
        return -1;      // 如果是'-',说明是空结点,返回-1
    } else {
        if(strlen(id) == 1) return id[0] - '0';     // 编号小于10
        else return (id[0] - '0') * 10 + (id[1] - '0');     // 编号大于等于10
    }
}
// findRoot函数找到根结点编号
int findRoot(int n) {
    for(int i = 0; i < n; i++) {
        if(isRoot[i]) {     // isRoot为true时直接返回根结点编号i
            return i;
        }
    }
}
// BFS函数判断完全二叉树,root为根结点编号,last是最后一个结点编号(注意引用),n为结点个数
bool BFS(int root, int &last, int n) {
    queue<int> q;       // 定义队列
    q.push(root);       // 根结点入队
    while(n) {      // 只要n不为0,即还没有访问完全部非空结点
        int front = q.front();      // 队首结点front
        q.pop();        // 弹出队首结点
        if(front == -1) return false;   // 访问到空结点,一定是非完全二叉树
        n--;    // 已访问的非空结点减少1
        last = front;   // 记录最后一个非空结点编号
        q.push(node[front].left);       // 左孩子入队(包括空结点)
        q.push(node[front].right);      // 右孩子入队(包括空结点)
    }
    return true;    // 已经访问完所有非空结点,还没有碰到空结点,一定是完全二叉树
}
int main() {
    int n;
    scanf("%d", &n);    // 输入结点个数
    memset(isRoot, true, sizeof(isRoot));       //初始化所有结点都是根结点
    for(int i = 0; i < n; i++) {        // 对每一个结点
        int left = input(), right = input();    // 输入左右孩子编号
        isRoot[left] = isRoot[right] = false;   // 这两个编号一定不是根结点
        node[i].left = left;        // 记录左孩子
        node[i].right = right;      // 记录右孩子
    }
    int root = findRoot(n), last;       // 寻找根结点root,定义最后一个结点last
    bool isCompleteTree = BFS(root, last, n);      // 判断完全二叉树,同时记录最后一个结点last
    if(isCompleteTree) {        // 如果是完全二叉树
        printf("YES %d\n", last);   // 输出最后一个结点编号
    } else {
        printf("NO %d\n", root);    // 否则输出根结点编号
    }
    return 0;
}

Code 02

#include <iostream>
#include <queue>
using namespace std;
const int maxn=20;
int last=-1;
int flag[maxn];
struct node {
	int d;
	int left=-1;
	int right=-1;
} nds[maxn];
bool bfs(int r) {
	queue<int> q;
	q.push(r);
	while(!q.empty()) {
		int now = q.front();
		q.pop();
		if(now!=-1) { // 非空节点 
			last = now;
			q.push(nds[now].left); 
			q.push(nds[now].right);
		} else { // 空节点 
			//检验后面是否还有非-1的数
			while(!q.empty()) {
				int nw = q.front();
				q.pop();
				if(nw!=-1)return false; //如果NULL后有非NULL节点,非完全二叉树 
			}
		}
	}
	return true;
}
int main(int argc,char * argv[]) {
	int n;
	scanf("%d",&n);
	string f,r;
	for(int i=0; i<n; i++) {
		cin>>f>>r;
		nds[i].d=i;
		if(f!="-") {
			nds[i].left=stoi(f);
			flag[nds[i].left]=1;
		}
		if(r!="-") {
			nds[i].right=stoi(r);
			flag[nds[i].right]=1;
		}
	}
	//find root;
	int k=0;
	while(k<n&&flag[k]==1)k++;
	bool ff = bfs(k);
	if(ff) {
		printf("%s %d","YES",last);
	} else {
		printf("%s %d","NO",k);
	}

	return 0;
}

Code 03

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=20;
int flag[maxn];
struct node {
	int data;
	int index;
	int left=-1;
	int right=-1;
} nds[maxn];
void dfs(int root,int index) {
	if(root==-1)return;
	nds[root].index=index;
	dfs(nds[root].left,2*index+1);
	dfs(nds[root].right,2*index+2);
}
bool cmp(node &n1,node &n2){
	return n1.index<n2.index;
}
int main(int argc,char * argv[]) {
	int n;
	scanf("%d",&n);
	string f,r;
	for(int i=0; i<n; i++) {
		cin>>f>>r;
		nds[i].data=i; 
		if(f!="-") {
			nds[i].left=stoi(f);
			flag[nds[i].left]=1;
		}
		if(r!="-") {
			nds[i].right=stoi(r);
			flag[nds[i].right]=1;
		}
	}
	//find root;
	int k=0;
	while(k<n&&flag[k]==1)k++;
	dfs(k,0);
	sort(nds,nds+n,cmp);
	/**
		判断当前树是否为完全二叉树:
		方式一:遍历所有节点,前后节点index相差1
		方式二:完全二叉树的所有节点最大index为n 
	*/
	bool iscbt=true;
	for(int i=1; i<n; i++) {
		if(nds[i].index-nds[i-1].index!=1) {
			iscbt=false;
		}
	}
	if(iscbt)printf("YES %d",nds[n-1].data);
	else printf("NO %d", nds[0].data);
	return 0;
}

Code 04

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=20;
int flag[maxn];
struct node {
	int left=-1;
	int right=-1;
} nds[maxn];
int max_n,max_i;
void dfs(int root,int index) {
	if(root==-1)return;
	if(max_i<index) {
		max_i=index;
		max_n=root;
	}
	dfs(nds[root].left,2*index+1);
	dfs(nds[root].right,2*index+2);
}
int main(int argc,char * argv[]) {
	int n;
	scanf("%d",&n);
	string f,r;
	for(int i=0; i<n; i++) {
		cin>>f>>r;
		if(f!="-") {
			nds[i].left=stoi(f);
			flag[nds[i].left]=1;
		}
		if(r!="-") {
			nds[i].right=stoi(r);
			flag[nds[i].right]=1;
		}
	}
	//find root;
	int k=0;
	while(k<n&&flag[k]==1)k++;
	dfs(k,0);
	/**
		判断当前树是否为完全二叉树:
		方式一:遍历所有节点,前后节点index相差1
		方式二:完全二叉树的所有节点最大index为n
	*/
	if(max_i==n-1)printf("YES %d",max_n);
	else printf("NO %d", k);
	return 0;
}
posted @ 2020-02-20 15:30  JamieHou  阅读(124)  评论(0编辑  收藏  举报