PAT A1123 Is It a Complete AVL Tree

PAT A1123 Is It a Complete AVL Tree

在这里插入图片描述

  • 思路 1:
  1. 建树
  2. 层序遍历,初始起点的id即为1,每次将当前出队节点now的id在has表里标记上,now的左孩子id为:2 * now->id,右孩子id:2 * now->id + 1
  3. 遍历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; 
}

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;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值