PAT A1123 Is It a Complete AVL Tree
- 思路 1:
- 建树
- 层序遍历,初始起点的id即为1,每次将当前出队节点now的id在has表里标记上,now的左孩子id为:
2 * now->id
,右孩子id:2 * now->id + 1
- 遍历has表,如果1~n有点未被标记:不是完全二叉树,否则YES:如果是完全二叉树,按id记录下来的节点,一定是从1到n连续的
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 50;
int insertion[maxn];
struct node{
int data, height, id;
node *lc, *rc;
node(){lc = rc = NULL; height = 1;} //Wrong 1:初始树高为1:别写成0了
};
int getHeight(node* r){
if(r == NULL) return 0; //Wrong 2:getHeight()别忘了r==NULL的情况,空树高度0
return r->height;
}
void updateHeight(node* r){
r->height = max(getHeight(r->lc), getHeight(r->rc)) + 1;
}
int getBalanceFactor(node* r){
return getHeight(r->lc) - getHeight(r->rc);
}
void L(node* &r){
node* tmp = r->rc;
r->rc = tmp->lc;
tmp->lc = r;
updateHeight(r);
updateHeight(tmp); ///!!!Wrong 3:顺序不能颠倒,要先更新下面的,再更新上面的
r = tmp;
}
void R(node* &r){
node* tmp = r->lc;
r->lc = tmp->rc;
tmp->rc = r;
updateHeight(r);
updateHeight(tmp);
r = tmp;
}
void insert(node* &r, int x){ //Wrong 4:返回值为viod:直接r上操作,不需要返回root了(node*)
if(r == NULL){
r = new node;
r->data = x;
return;
}
if(x < r->data){
insert(r->lc, x);
updateHeight(r);
if(getBalanceFactor(r) == 2){
if(getBalanceFactor(r->lc) == 1){ //LL
R(r);
}else if(getBalanceFactor(r->lc) == -1){ //LR
L(r->lc);
R(r);
}
}
}else{
insert(r->rc, x);
updateHeight(r);
if(getBalanceFactor(r) == -2){
//!!!:Wrong 5:复制过来,千万不要忘记改rc/lc
if(getBalanceFactor(r->rc) == -1){ //RR
L(r);
}else if(getBalanceFactor(r->rc) == 1){ //RL
R(r->rc);
L(r);
}
}
}
}
node* create(int n){
node* r = NULL;
for(int i = 0; i < n; ++i)
insert(r, insertion[i]);
return r;
}
vector<int> ans;
int levelo[maxn];
void levelOrder(node* r){
queue<node*> q;
r->id = 1;
q.push(r);
while(!q.empty()){
node* now = q.front();
ans.push_back(now->data);
levelo[now->id] = 1;
q.pop();
if(now->lc != NULL){
now->lc->id = now->id * 2;
q.push(now->lc);
}
if(now->rc != NULL){
now->rc->id = now->id * 2 + 1;
q.push(now->rc);
}
}
}
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; ++i){
scanf("%d", &insertion[i]);
}
node* root = create(n);
levelOrder(root);
for(int i = 0; i < ans.size(); ++i){
if(i == 0) printf("%d", ans[0]);
else printf(" %d", ans[i]);
}
bool flag = false;
for(int i = 1; i <= n; ++i){
if(levelo[i] == 0){
flag = true;
}
}
printf("\n%s", flag ? "NO" : "YES");
return 0;
}
-
AVL:注意事项
-
Wrong 1:
一个节点的树的高度初始为1 -
Wrong 2:
getHeight()别忘了r==NULL的情况,空树高度0 -
Wrong 3:
左旋右旋操作后,更新r和tmp高度的顺序不能颠倒,要先更新下面的,再更新上面的(因为更新前r和tmp还没交换,所有tmp在上,先更新r) -
Wrong 4:
注意返回值类型,如这里插入和L/R都是通过在传入参数node* &root
直接修改,故返回值为viod:直接r上操作,不需要返回root了 -
Wrong 5:
插入里的左右判断,如果直接把左的情况复制粘贴到右的情况,千万不要忘记改rc/lc -
TIPS 1:
可以改为后序遍历递归查高度,省去了updateHeight()
int getHeight(node *tree){
if (tree == NULL) return 0;
int l = getHeight(tree->left);
int r = getHeight(tree->right);
return max(l, r) + 1;
}
- 思路1-2:先序存入数组法:同PAT A1064 Complete Binary Search Tree、PAT A1066 Root of AVL Tree
step 1:建树后,通过先序遍历将树存入heap数组(初始化为INF),期间若有元素下标超过n,说明不是CBT
step 2:右往左依次输出数组中非INF元素,即为层序遍历序列
- T2 code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 50, INF = 0xfffffff;
struct node{
int data, height;
node *lc, *rc;
};
node* NewNode(int x){
node* r = new node;
r->data = x;
r->lc = r->rc = NULL;
r->height = 1;
return r;
}
int GetHeight(node* r){
return r == NULL ? 0 : r->height;
}
void UpdateHeight(node* r){
r->height = max(GetHeight(r->lc), GetHeight(r->rc)) + 1;
}
int GetBalanceFactor(node* r){
return GetHeight(r->lc) - GetHeight(r->rc);
}
void L(node* & r){
node* tmp = r->rc;
r->rc = tmp->lc;
tmp->lc = r;
UpdateHeight(r);
UpdateHeight(tmp);
r = tmp;
}
void R(node* & r){
node* tmp = r->lc;
r->lc = tmp->rc;
tmp->rc = r;
UpdateHeight(r);
UpdateHeight(tmp);
r = tmp;
}
void Insert(node* & r, int x){
if(r == NULL){
r = NewNode(x);
return;
}
if(r->data > x){
Insert(r->lc, x);
UpdateHeight(r);
if(GetBalanceFactor(r) == 2){
if(GetBalanceFactor(r->lc) == -1) L(r->lc);
R(r);
}
}else{
Insert(r->rc, x);
UpdateHeight(r);
if(GetBalanceFactor(r) == -2){
if(GetBalanceFactor(r->rc) == 1) R(r->rc);
L(r);
}
}
}
int heap[maxn];
bool flag = true;
void PreOrder(int id, int n, node* r){
if(r == NULL) return;
PreOrder(2 * id, n, r->lc);
if(id > n) flag = false;
heap[id] = r->data;
PreOrder(2 * id + 1, n, r->rc);
}
int main(){
int n, tmp;
scanf("%d", &n);
node* r = NULL;
for(int i = 0; i < n; ++i){
scanf("%d", &tmp);
Insert(r, tmp);
}
fill(heap, heap+maxn, INF);
PreOrder(1, n, r);
for(int i = 1; i < maxn; ++i){
if(i == 1) printf("%d", heap[i]);
else if(heap[i] != INF) printf(" %d", heap[i]);
}
printf("\n%s", flag ? "YES" : "NO");
return 0;
}
-
思路 2:柳神的思路
如果一个孩子节为空,后面所有孩子节点都不会空了,否则就不是完全二叉树
类似进程同步互斥,当有孩子空时,lock开锁,后面如果还有进入if(lock)的说明后面还有不空节点,标记为false -
code 2:
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 50;
int insertion[maxn];
struct node{
int data;
node *lc, *rc;
node(){lc = rc = NULL;}
};
int getHeight(node* r){
if(r == NULL) return 0;
int lH = getHeight(r->lc);
int rH = getHeight(r->rc);
return max(lH, rH) + 1;
}
void L(node* &r){
node* tmp = r->rc;
r->rc = tmp->lc;
tmp->lc = r;
r = tmp;
}
void R(node* &r){
node* tmp = r->lc;
r->lc = tmp->rc;
tmp->rc = r;
r = tmp;
}
void insert(node* &r, int x){
if(r == NULL){
r = new node;
r->data = x;
return;
}
// int lH = getHeight(r->lc), rH = getHeight(r->rc); //!!!Wrong 1:必须放到里面!WHY?
if(x < r->data){
insert(r->lc, x);
int lH = getHeight(r->lc), rH = getHeight(r->rc);
if(lH - rH >= 2){
if(x < r->lc->data) R(r); //LL
else{ //LR
L(r->lc);
R(r);
}
}
}else{
insert(r->rc, x);
int lH = getHeight(r->lc), rH = getHeight(r->rc);
if(rH - lH >= 2){
if(x > r->rc->data) L(r); //RR
else{ //RL
R(r->rc);
L(r);
}
}
}
}
node* create(int n){
node* r = NULL;
for(int i = 0; i < n; ++i)
insert(r, insertion[i]);
return r;
}
bool isComplete = true, lock = false;
vector<int> ans;
void levelOrder(node* r){
queue<node*> q;
q.push(r);
while(!q.empty()){
node* now = q.front();
q.pop();
ans.push_back(now->data);
if(now->lc != NULL){
if(lock) isComplete = false;
q.push(now->lc);
}else lock = true;
if(now->rc != NULL){
if(lock) isComplete = false;
q.push(now->rc);
}else lock = true;
}
}
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; ++i){
scanf("%d", &insertion[i]);
}
node* root = create(n);
levelOrder(root);
for(int i = 0; i < ans.size(); ++i){
if(i == 0) printf("%d", ans[0]);
else printf(" %d", ans[i]);
}
printf("\n%s", isComplete ? "YES" : "NO");
return 0;
}
- T4 code:
#include <bits/stdc++.h>
using namespace std;
struct node
{
int data, height;
node *lc, *rc;
};
node* NewNode(int x)
{
node* r = new node;
r->data = x;
r->height = 1;
r->lc = r->rc = nullptr;
return r;
}
int GetHeight(node* r) { return r == nullptr ? 0 : r->height; }
void UpdateHeight(node* r) { r->height = max(GetHeight(r->lc), GetHeight(r->rc)) + 1; }
int GetBalanceFactor(node* r) { return GetHeight(r->lc) - GetHeight(r->rc); }
void L(node* & r)
{
node* tmp = r->rc;
r->rc = tmp->lc;
tmp->lc = r;
UpdateHeight(r);
UpdateHeight(tmp);
r = tmp;
}
void R(node* & r)
{
node* tmp = r->lc;
r->lc = tmp->rc;
tmp->rc = r;
UpdateHeight(r);
UpdateHeight(tmp);
r = tmp;
}
void Insert(node* & r, int x)
{
if(r == nullptr)
{
r = NewNode(x);
}else if(x < r->data)
{
Insert(r->lc, x);
UpdateHeight(r);
if(GetBalanceFactor(r) == 2)
{
if(GetBalanceFactor(r->lc) == -1) L(r->lc);
R(r);
}
}else
{
Insert(r->rc, x);
UpdateHeight(r);
if(GetBalanceFactor(r) == -2)
{
if(GetBalanceFactor(r->rc) == 1) R(r->rc);
L(r);
}
}
}
struct v
{
int data, id;
bool operator < (const v & tmp) const { return id < tmp.id; }
};
set<v> ans;
void Pre(node* r, bool & isCBT, int id, int n)
{
if(r == nullptr) return;
if(id > n) isCBT = false;
ans.insert(v{r->data, id});
Pre(r->lc, isCBT, 2 * id, n);
Pre(r->rc, isCBT, 2 * id + 1, n);
}
int main()
{
int n;
scanf("%d", &n);
node* r = nullptr;
for(int i = 0; i < n; ++i)
{
int tmp;
scanf("%d", &tmp);
Insert(r, tmp);
}
bool isCBT = true;
Pre(r, isCBT, 1, n);
for(auto it = ans.begin(); it != ans.end(); ++it)
{
if(it == ans.begin()) printf("%d", it->data);
else printf(" %d", it->data);
}
printf("\n%s", isCBT ? "YES" : "NO");
return 0;
}