PAT (Advanced Level) Practice 1066 Root of AVL Tree 眼瞎只能怪自己

一、概述

建一棵AVL树。

代码挺复杂的,我调了一下午,因为有一个错误和一个段错误。

实际上最后发现错误就是一个本应是=的地方我打成了==。

一切需要复制黏贴的地方,都容易出错。

简直气死。

二、分析

首先,我们要明确这一点,AVL树是BST进化而来的。所以建AVL树也和建BST树大体上差不多。

一般插入法建树我们使用引用法,即声明一个insert函数,变量是node*&和int,把int作为节点插到root上。

先判断,如果是空的那就直接插,如果不是空的,小于往左插大于等于往右插。

建AVL树的框架也是这样。

但是多了几步:因为AVL树要求两子树高度相差不超过一。

求高度的函数如下:

int getHeight(node* root)
{
	if(root==NULL)
	return 0;
	return root->height;
}

因此在插完之后,首先更新所插节点的高度。

如何更新高度呢?函数如下:

void updateHeight(node* root)
{
	root->height=max(getHeight(root->lchild),getHeight(root->rchild))+1;
 } 

无返回值,参数为node*。

直接令root高度为两子树高度最大的那个加一。

然后判断root的平衡因子是否合法。要判断就要知道root的平衡因子,如下:

int getBalanceFactor(node* root)
{
	return getHeight(root->lchild)-getHeight(root->rchild);
 } 

平衡因子就是左子树高度减去右子树高度。

然后把所有情况分为以下几种:

合法的:平衡因子等于0,1,-1;

不合法的:平衡因子等于2,-2。

这里注意一点,只有往左子树插,才可能出现2,往右子树插,才可能出现-2。

因此在左子树插完,判断是否为2即可。

如果是2,说明不再平衡,这里又有两种情况:

左子树的平衡因子为1或-1。

当平衡因子为1时,说明是LL型,直接将根节点右旋一次;

当平衡因子为-1时,说明是LR型,将左子树左旋,再将根节点右旋。

那么,左旋和右旋分别怎么写呢?如下:

//左旋
//左旋是让根节点的右子树当根节点 
 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;
 }

这最好用笔画一下,左旋就是(右子树)往左跳,右旋就是(左子树)往右跳。

注意返回值为空,参数要引用。

当平衡因子为-2时也类似。

于是树就建好了。

三、总结

建AVL树的模板最好记下来。注意节点的平衡因子不用保存,而高度需要保存。

总结起来三大基础函数(求节点高度,求平衡因子,更新高度),两大功能函数(左旋,右旋),一大插入函数。

PS:代码如下:

#include<cstdio>
#include<algorithm>
using namespace std;
struct node
{
	int v,height;
	node* lchild,*rchild;
}*root;
//获得当前节点的高度
int getHeight(node* root)
{
	if(root==NULL)
	return 0;
	return root->height;
}
//更新当前节点高度 
void updateHeight(node* root)
{
	root->height=max(getHeight(root->lchild),getHeight(root->rchild))+1;
 } 
//获得当前节点的平衡因子
int getBalanceFactor(node* root)
{
	return getHeight(root->lchild)-getHeight(root->rchild);
 } 
//左旋
//左旋是让根节点的右子树当根节点 
 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;
 }
node* newnode(int a)
{
	node* root=new node;
	root->v=a;
	root->height=1;
	root->lchild=root->rchild=NULL;
	return root;
}
void insert(node* &root,int a)
{
	if(root==NULL)
	{
		root=newnode(a);
		return;
	}
	else
	{
		if(a<root->v)
		{
			insert(root->lchild,a);//往左子树插 
			updateHeight(root);
			if(getBalanceFactor(root)==2)//不平衡,那一定是根节点在往左子树查之后平衡因子变为2 
			{
				if(getBalanceFactor(root->lchild)==1)//左子树的平衡因子为一,说明插到LL
				{
					R(root);//对根节点进行右转 
				 } 
				 else if(getBalanceFactor(root->lchild)==-1)//左子树平衡因子为负一,说明插到LR
				 {
				 	L(root->lchild);//首先左转,把LR变成LL
					 R(root);//然后按LL做 
				 } 
			}
		}
		else
		{
			insert(root->rchild,a);
			updateHeight(root);
			if(getBalanceFactor(root)==-2)//不平衡,那一定是根节点往右子树插之后平衡因子变为-2
			{
				if(getBalanceFactor(root->rchild)==-1)//右子树平衡因子为负一,说明插到RR
				{
					L(root);//对根节点进行左转 
				}
				else if(getBalanceFactor(root->rchild)==1)//右子树平衡节点为一,说明插到RL
				{
					R(root->rchild);//首先右转,把RL变为RR 
					L(root);//然后按RR做 
				}
			} 
		 } 
	}
}
int main()
{
	int n,v;
 	scanf("%d",&n);
 	for(int i=0;i<n;i++)
 	{
 		scanf("%d",&v);
 		insert(root,v);
	 }
	 int ans=root->v;
	printf("%d\n",ans);
 } 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值