A1123
Description:
给出一组数,求这组数所构成的平衡二叉树的层次遍历序列,并回答其是否为完全二叉树;
思路:
-
老老实实建树,有关插入部分代码如果有丝毫不理解,强烈建议去找一个动画版本观察,然后自己动手画一画,过程了然于胸之后,再看代码落实,背诵模板如下:
struct node{ int v, height; //height存放该节点子树的最大高度,默认为自己,高度=1 node *lchild, *rchild; }; node *newNode(int v){ node* Node = new node; Node->v = v; Node->height = 1; //新建节点高度为1 Node->lchild = Node->rchild = NULL; return Node; } int getHeight(node *root){ //获得root节点子树最大高度 if(root == NULL) return 0; //root树不存在返回0 return root->height; } int getBalance(node* root){ //获得root节点平衡因子 return getHeight(root->lchild) - getHeight(root->rchild);//左孩子高度-右孩子高度即为平衡因子 } void updateHeight(node* root){ //更新root节点最大高度,插入节点后立即更新 root->height = max(getHeight(root->lchild), getHeight(root->rchild))+1; //更新为左右子树的高度的最大值+1 } void L(node* &root){ //左旋,右侧较高 node* temp = root->rchild; //将右孩子暂存 root->rchild = temp->lchild; //将右孩子的左孩子给原根右孩子 temp->lchild = root; //将原根作为右孩子的左孩子 updateHeight(root); //更新原根高度 updateHeight(temp); //更新新根(右孩子)高度 root = temp; //将指向原根的指针指向新根(右孩子) } void R(node* &root){ //和左旋完全镜像,左右身份互换 node* temp = root->lchild; root->lchild = temp->rchild; temp->rchild = root; updateHeight(root); updateHeight(temp); root = temp; } void insertNode(node* &root, int v){ //插入新节点 if(root == NULL){ //树是空的,该节点即放置在该位置 root = newNode(v); return ; } if(v < root->v){ //小于现根节点 insertNode(root->lchild, v); //递归插入至左子树中 updateHeight(root); //插入完毕后更新根节点 if(getBalance(root) == 2){ //根节点==2失衡,即左子树太高 if(getBalance(root->lchild) == 1){ //左子树==1,即左子树的左子树较高 R(root); //物极必反,简单右旋 }else if(getBalance(root->lchild) == -1){ //左子树==-1,即左子树的右子树较高 L(root->lchild); //解决局部矛盾,左旋左子树 R(root); //右旋根节点 } } } else{ //大于现根节点,剩下的操作和小于根节点完全镜像,左右身份互换 insertNode(root->rchild, v); updateHeight(root); if(getBalance(root) == -2){ if(getBalance(root->rchild) == -1){ L(root); }else if(getBalance(root->rchild) == 1){ R(root->rchild); L(root); } } } }
-
判断二叉树是否为完全二叉树思路:层次遍历树,根据节点左右子树存在情况进行判断:
- 若某节点左子树空,则该节点右子树必须为空,否则非完全二叉树;
- 若某节点左子树空,则该节点往后的节点均不可有非空的左右子树;
- 若某节点右子树空,则该节点往后的节点同样均不可有非空的左右子树;
核心代码参考的柳神:
bool isCom;//isCom用于表示该二叉树是否为完全二叉树,1为是,0为不是 bool after;//after用于标志往后还能不能有非空节点,1表示可以,0表示不行 void bfs(node* root){ queue<node*>q; isCom = true; //初始化,假设为完全二叉树 after = true; //可以有非空节点 q.push(root); //当前根节点入队 while(!q.empty()){ node* now = q.front(); ans.push_back(now->v); if(now->lchild!=NULL){ //左子树非空 if(after==false) isCom = false; //判断该左子树是否可以存在,若after==false,则表示该左子树不可存在,标志非完全二叉树 q.push(now->lchild); }else after = false; //左子树为空,后继将不能再有非空节点 if(now->rchild!=NULL){ //同上 if(after==false) isCom = false; q.push(now->rchild); }else after = false; q.pop(); } }
-
AC代码
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 25;
int num[maxn], n;
struct node{
int v, height; //height存放该节点子树的最大高度,默认为自己,高度=1
node *lchild, *rchild;
};
node *newNode(int v){
node* Node = new node;
Node->v = v;
Node->height = 1; //新建节点高度为1
Node->lchild = Node->rchild = NULL;
return Node;
}
int getHeight(node *root){ //获得root节点子树最大高度
if(root == NULL) return 0; //root树不存在返回0
return root->height;
}
int getBalance(node* root){ //获得root节点平衡因子
return getHeight(root->lchild) - getHeight(root->rchild);//左孩子高度-右孩子高度即为平衡因子
}
void updateHeight(node* root){ //更新root节点最大高度,插入节点后立即更新
root->height = max(getHeight(root->lchild), getHeight(root->rchild))+1; //更新为左右子树的高度的最大值+1
}
void L(node* &root){ //左旋,右侧较高
node* temp = root->rchild; //将右孩子暂存
root->rchild = temp->lchild; //将右孩子的左孩子给原根右孩子
temp->lchild = root; //将原根作为右孩子的左孩子
updateHeight(root); //更新原根高度
updateHeight(temp); //更新新根(右孩子)高度
root = temp; //将指向原根的指针指向新根(右孩子)
}
void R(node* &root){ //和左旋完全镜像,左右身份互换
node* temp = root->lchild;
root->lchild = temp->rchild;
temp->rchild = root;
updateHeight(root);
updateHeight(temp);
root = temp;
}
void insertNode(node* &root, int v){ //插入新节点
if(root == NULL){ //树是空的,该节点即放置在该位置
root = newNode(v);
return ;
}
if(v < root->v){ //小于现根节点
insertNode(root->lchild, v); //递归插入至左子树中
updateHeight(root); //插入完毕后更新根节点
if(getBalance(root) == 2){ //根节点==2失衡,即左子树太高
if(getBalance(root->lchild) == 1){ //左子树==1,即左子树的左子树较高
R(root); //物极必反,简单右旋
}else if(getBalance(root->lchild) == -1){ //左子树==-1,即左子树的右子树较高
L(root->lchild); //解决局部矛盾,左旋左子树
R(root); //右旋根节点
}
}
}
else{ //大于现根节点,剩下的操作和小于根节点完全镜像,左右身份互换
insertNode(root->rchild, v);
updateHeight(root);
if(getBalance(root) == -2){
if(getBalance(root->rchild) == -1){
L(root);
}else if(getBalance(root->rchild) == 1){
R(root->rchild);
L(root);
}
}
}
}
vector<int>ans;
bool isCom;//isCom用于表示该二叉树是否为完全二叉树,1为是,0为不是
bool after;//after用于标志往后还能不能有非空节点,1表示可以,0表示不行
void bfs(node* root){
queue<node*>q;
isCom = true; //初始化,假设为完全二叉树
after = true; //可以有非空节点
q.push(root); //当前根节点入队
while(!q.empty()){
node* now = q.front();
ans.push_back(now->v);
if(now->lchild!=NULL){ //左子树非空
if(after==false) isCom = false; //判断该左子树是否可以存在,若after==false,则表示该左子树不可存在,标志非完全二叉树
q.push(now->lchild);
}else after = false; //左子树为空,后继将不能再有非空节点
if(now->rchild!=NULL){ //同上
if(after==false) isCom = false;
q.push(now->rchild);
}else after = false;
q.pop();
}
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
scanf("%d", &n);
node* root = NULL;
for(int i = 0; i < n; i++){
scanf("%d", &num[i]);
insertNode(root, num[i]);
}
bfs(root);
for(int i = 0; i < ans.size(); i++){
if(i) printf(" ");
printf("%d", ans[i]);
}
if(isCom) printf("\nYES");
else printf("\nNO");
return 0;
}