7-2 是否完全二叉搜索树
分数 30
将一系列给定数字顺序插入一个初始为空的二叉搜索树(定义为左子树键值大,右子树键值小),你需要判断最后的树是否一棵完全二叉树,并且给出其层序遍历的结果。
输入格式:
输入第一行给出一个不超过20的正整数N
;第二行给出N
个互不相同的正整数,其间以空格分隔。
输出格式:
将输入的N
个正整数顺序插入一个初始为空的二叉搜索树。在第一行中输出结果树的层序遍历结果,数字间以1个空格分隔,行的首尾不得有多余空格。第二行输出YES
,如果该树是完全二叉树;否则输出NO
。
样例1:">样例1:">样例1:">样例1:">输入样例1:
9
38 45 42 24 58 30 67 12 51
输出样例1:
38 45 24 58 42 30 12 67 51
YES
输入样例2:
8
38 24 12 45 58 67 42 51
输出样例2:
38 45 24 58 42 12 67 51
NO
在写之前需要先明确完全二叉树的概念。如果给每一个节点按顺序编号1,2,3....,那么只有编号和完美二叉树中每一个节点的编号是一致的能成为是完全二叉树。所以一个完全二叉树要么没有度为一的节点,要么只有一个,下面分两种情况,一种是有度为一的节点,一种是没有度为一的节点。(对题目中涉及的二叉搜索树插入和层序遍历不做解释)
有度为一的节点:
增加一个book数组来标记每一个节点是否拥有左右节点,设置一个全局变量来让它代表当前节点的编号。
可以在进行层序遍历时,在左右子节点入队的时候,如果有左节点,book[i]加1,如果有右节点,book[i]要加2,这样操作之后,一个节点如果book值为0,1,2,3,分别对应四种情况。
(1)当度为一的节点的子节点为左节点时:
当前节点后面的兄弟节点就不能拥有子节点,即它的子节点就是最后一个节点。(如果它已经是当前层最后一个节点,即它没有后面的兄弟节点依旧适用)
(2)当子节点为右节点时:
book的标记值为2,只要满足这个条件,就说明它不是完全二叉树。
(可以自己画图画一下)
没有度为一的节点:
依然需要book数组,和前面操作一样。
当它只有度为二和度为零的节点时,要让它不是一个完全二叉树,只能在度为二的节点的前方出现叶子节点,所以可以在找到第一个叶子节点时,使用for循环从当前节点+1开始遍历,如果有book[j]不为0,就不是完全二叉树。
至此所有情况讨论完毕。(不知道有没有遗漏,反正PTA过了,为了留存自己写的代码,方便以后缅怀我曾经的代码)
还可以用第二种方法,层序遍历时用book数组的值记录每一个节点的编号,book[1]=1,如果有一个节点它的左右子节点是空的话,就把它的左右子节点的book值设为0,book[i*2]和book[2*i+1],再遍历book数组,如果找到book[i]=0,以此为起点再遍历整个数组(i终止值不为n,自己想一想why),如果有不为0的,就是不完全二叉树输出NO。
#include<iostream>
#include<queue>
using namespace std;
typedef struct TNode *Bintree;
int book[21],j=1; //标记数组,用来判断当前节点的左右节点状况
struct TNode{
Bintree Left;
Bintree Right;
int Data;
};
Bintree Insert(Bintree BST,int x){ //插入函数,不做解释
if(BST==NULL){
BST=(Bintree)malloc(sizeof(struct TNode));
BST->Data=x;
BST->Left=NULL;
BST->Right=NULL;
}
else{
if(BST->Data>x){
BST->Right=Insert(BST->Right,x);
}
else
BST->Left=Insert(BST->Left,x);
}
return BST;
}
void floor(Bintree BST){ //层序遍历,不做解释
queue<Bintree> q;
if(BST!=NULL)
q.push(BST);
while(!q.empty()){
if(q.front()->Left!=NULL){
q.push(q.front()->Left);
book[j]+=1;
}
if(q.front()->Right!=NULL){
q.push(q.front()->Right);
book[j]+=2;
}
cout<<q.front()->Data;
q.pop();
if(!q.empty())
cout<<" ";
j++;
}
}
int main(){
Bintree BST;
int n,flag=0;
int a[21];
BST=NULL;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
BST=Insert(BST,a[i]);
}
floor(BST);
cout<<endl;
//------------------------------------------重点部分
for(int i=1;i<=n;i++){
if((book[i]==1&&(2*i)!=n)||(book[i]==2)){ //检查所有节点的左右子节点的情况
flag=1; //只有左节点,但是左节点不是最后一个节点,只有右节点都不是完全的
break;
}
if(book[i]==0) //没有度为一的节点情况
{
for(int j=i+1;j<=n;j++){
if(book[j]!=0){
flag=1;
break;
}
}
}
}
if(flag==0)
cout<<"YES";
else
cout<<"NO";
}