PAT (Advanced Level) Practice 1110 Complete Binary Tree 判断完全二叉树

一、概述

25分题,正常来讲应该45分钟之内做完,我用了快90分钟,日日了狗不说,还没AC。

究其原因,在于我做这道题时,只想着从最直观的角度出发,用人脑的方式,也就是我平常的判断方式,判断一棵树是否是完全二叉树,这是不行的,按我的方法:

先建树;

BFS得到各节点层数以及每层的节点,按顺序;

BFS得到树高;

根据树高,先从第一层到倒数第二层,看节点数量是不是满的;

若不是满的,则不是完全二叉树;

若是满的,则看倒数第二层;

分四种情况:

左右皆不空,左右皆空,左空右不空,左不空右空;

按照层中节点的顺序往右,第一种在之前出现过空的时候可以return,第二种若前边不空则置标志位为空;第三种同第二种;第四种直接return。

太麻烦了。我同时维护了近十个数组,活生生把算法题做成了模拟题。

实际上,应该按如下方法做:

首先建树。建完后给所有节点编号,假装是完全二叉树的那种编号,就是根节点是n,左孩子2n右孩子2n+1。然后看最大的编号是不是和节点数量相同,相同则是完全二叉树,否则不是。

以样例的第二个为例,他不是完全二叉树。因为7的编号为7,0的编号为8,6的编号为9,这样一来,最大编号9大于总数8。说明不是。简单得多。

使用DFS给节点编号。

二、分析

虽然我这个特别蠢,可是往好了想,也是练习了BFS、层数、求各层节点嘛。(还是太蠢了,蠢哭了)

下面分析AC代码。

首先是输入,选择使用静态树。也就是开一个节点数组,往里面存,不使用指针。如下:

struct Node
{
	int root=0;
	int lchild=-1,rchild=-1;
};
Node BitTree[25];

然后使用一个数组记录哪些节点不可能是根节点——那些出现在孩子节点的就肯定不是了。然后输入:

发现输入可能有两种,一种是0到9,一种是-;

因此使用string输入,并与-比较,不是-那就使用stoi将string转为int。

注意,stoi函数使用要事先将编译设置好,工具,编译选项,设置,生成代码,语言标准,c++11,不然会报错。

然后输入即可。如下:

for(int i=0;i<N;i++)
	{
		string l,r;
		int lchild;
		int rchild;
		cin>>l;
		cin>>r;
		if(l=="-")
		lchild=-1;
		else
		lchild=stoi(l);
		if(r=="-")
		rchild=-1;
		else
		rchild=stoi(r);
		if(lchild==-1)
		BitTree[i].lchild=-1;
		else
		{
			BitTree[i].lchild=lchild;
			rootNode[lchild]=0;
		}
		if(rchild==-1)
		BitTree[i].rchild=-1;
		else
		{
			BitTree[i].rchild=rchild;
			rootNode[rchild]=0;
		}
	}

输入的同时也就把根节点筛出来了。

然后使用DFS进行编号。由于编号随DFS变化,所以要作为参数输入。

每在DFS中调用一次DFS,编号乘二或者乘二加一,保存最大编号和最大编号对应的节点序号。最大序号是输出的时候要用到的。如下:

void DFS(int root,int index)
{
	if(index>maxindex)
	{
		ans=root;
		maxindex=index;
	}
	if(BitTree[root].lchild!=-1)
	DFS(BitTree[root].lchild,index*2);
	if(BitTree[root].rchild!=-1)
	DFS(BitTree[root].rchild,index*2+1);
}

利用的是完全二叉树左孩子序号为本身序号二倍,右孩子序号为二倍加一。

然后判断并输出。

三、总结

当看到题时,首先思考有无可利用的性质,不要直接开始模拟,太蠢了。

遇到的坑点有以下几个:

fill给二维数组赋值时,参数为a[0],a[0]+m*n,x,不加[0]是不行的。

二维数组的第一个表示第几行,第二个表示第几列。

以string输入时,判断字符串相等一定要用string==“”,用双引号而不是单引号。即是只有一个字符。

string转换为int时可以使用stoi函数,我自己傻不拉几写了一个,好蠢。

PS:我的代码:未AC,懒得debug了,心力交瘁

#include<stdio.h>
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<math.h>
#include<queue>
#include<algorithm>
using namespace std;
struct Node
{
	int root=0;
	int lchild=-1,rchild=-1;
	int level=0;
};
Node BitTree[25];
int rootNode[25];
int vis[25]={0};
int levelNode[10][10]; 
int levelnum[7]={0};
int level[7]={0,1,2,4,8,16,32};
int last=0;
void BFS(int root,int level)
{
	queue<int> q;
	q.push(root);
	BitTree[root].level=level;
	vis[root]=1;
	while(!q.empty())
	{
		int front=q.front();
		last=front;
		levelNode[BitTree[front].level][levelnum[BitTree[front].level]]=front;
		levelnum[BitTree[front].level]++;
		q.pop();
		if(BitTree[front].lchild!=-1&&vis[BitTree[front].lchild]==0)
		{
			BitTree[BitTree[front].lchild].level=BitTree[front].level+1;
			q.push(BitTree[front].lchild);
			vis[BitTree[front].lchild]=1;
		}
		if(BitTree[front].rchild!=-1&&vis[BitTree[front].rchild]==0)
		{
			BitTree[BitTree[front].rchild].level=BitTree[front].level+1;
			q.push(BitTree[front].rchild);
			vis[BitTree[front].rchild]=1;
		}
	}
}
int sti(string num)
{
	int sum=0;
	string::reverse_iterator it;
	int index=0;
	for(it=num.rbegin();it!=num.rend();it++)
	{
		sum+=(*it-'0')*pow(10,index);
		index++;
	}
	return sum;
}
int main()
{
	fill(rootNode,rootNode+25,1);
	fill(levelNode[0],levelNode[0]+36,-1);
	int N;
	scanf("%d",&N);
	for(int i=0;i<N;i++)
	{
		string l,r;
		int lchild;
		int rchild;
		cin>>l;
		cin>>r;
		if(l=="-")
		lchild=-1;
		else
		lchild=sti(l);
		if(r=="-")
		rchild=-1;
		else
		rchild=sti(r);
		if(lchild==-1)
		BitTree[i].lchild=-1;
		else
		{
			BitTree[i].lchild=lchild;
			rootNode[lchild]=0;
		}
		if(rchild==-1)
		BitTree[i].rchild=-1;
		else
		{
			BitTree[i].rchild=rchild;
			rootNode[rchild]=0;
		}
	}
	int root;
	for(int i=0;i<N;i++)
	{
		if(rootNode[i]==1)
		{
			root=i;
			break;
			}	
	}
	BFS(root,1);
	int maxlevel=0;
	for(int i=0;i<N;i++)
	{
		if(BitTree[i].level>maxlevel)
		{
			maxlevel=BitTree[i].level;
		}	
	}
	int valid=1;
	if(N<level[maxlevel])
	{
		printf("NO %d",root);
		return 0;
	}
	else
	{
	int childNull=0;
	int i;
	for(i=1;i<maxlevel;i++)
	{
	if(levelnum[i]!=level[i])
	{
		printf("NO %d",root);
		return 0;
	}
	}
	for(int j=0;j<levelnum[maxlevel-1];j++)
	{
		i=levelNode[maxlevel-1][j];
		if(BitTree[i].level==maxlevel-1)//如果他是最下面一层上面的一层 
		{
			if(BitTree[i].lchild==-1&&BitTree[i].rchild!=-1)//左空右不空 
			{
				printf("NO %d",root);
				return 0;
			}
			else if(BitTree[i].lchild!=-1&&BitTree[i].rchild!=-1)//左右都不空 
			{
				if(childNull==1)
				{
					printf("NO %d",root);
					return 0;
				}
				else
					continue; 
			}
			else if(BitTree[i].lchild!=-1&&BitTree[i].rchild==-1)
			{
				if(childNull==1)
				{
					printf("NO %d",root);
					return 0;
				}
				else
					childNull=1;
			}
			else
			{
				childNull=1;
			}
		}	
	}
	printf("Yes %d",last);
	}
}

AC代码如下:

#include<stdio.h>
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<math.h>
#include<queue>
#include<algorithm>
using namespace std;
struct Node
{
	int root=0;
	int lchild=-1,rchild=-1;
};
Node BitTree[25];
int rootNode[25];
int maxindex=-1;
int ans=-1;
void DFS(int root,int index)
{
	if(index>maxindex)
	{
		ans=root;
		maxindex=index;
	}
	if(BitTree[root].lchild!=-1)
	DFS(BitTree[root].lchild,index*2);
	if(BitTree[root].rchild!=-1)
	DFS(BitTree[root].rchild,index*2+1);
}
int main()
{
	fill(rootNode,rootNode+25,1);
	int N;
	scanf("%d",&N);
	for(int i=0;i<N;i++)
	{
		string l,r;
		int lchild;
		int rchild;
		cin>>l;
		cin>>r;
		if(l=="-")
		lchild=-1;
		else
		lchild=stoi(l);
		if(r=="-")
		rchild=-1;
		else
		rchild=stoi(r);
		if(lchild==-1)
		BitTree[i].lchild=-1;
		else
		{
			BitTree[i].lchild=lchild;
			rootNode[lchild]=0;
		}
		if(rchild==-1)
		BitTree[i].rchild=-1;
		else
		{
			BitTree[i].rchild=rchild;
			rootNode[rchild]=0;
		}
	}
	int root;
	for(int i=0;i<N;i++)
	{
		if(rootNode[i]==1)
		{
			root=i;
			break;
			}	
	}
	DFS(root,1);
	if(maxindex>N)
	{
		printf("NO %d",root);
	}
	else
	printf("YES %d",ans);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值