平衡二叉树之AVL树(一)

一.什么是AVL树?

      这个二叉树的每一个节点的左右子树高度之差的绝对值小于等于1.(好了 没了 就这么简单)

二.结构

     首先他是一个二叉树,二叉树该有的他都应该有,其次,他有一个东西,叫做平衡因子.

     什么是平衡因子,我的理解是他的左子树高度减去右子树的高度的值,就是平衡因子.

      好了,AVL的介绍就这么多.本文完.

--------------------------------------------------------------------------------------------------------------------






---------------------------------------------------------------------------------------

   怎么可能,都还没正式开始讲呢,我们拿出纸和笔,写一个普通的二叉树

比如说这个1,2,3吧,我们把3插入后有没发现问题,我们把3插入以后,他就不符合平衡二叉树的定义了啊(要问不符合什么定义的快仔细去看前面的红字)

那怎么办,Adelson-Velskii和Landis就想了这一个办法,旋转

怎么旋转?

我们把1掰下来,2放上去,然后,他又符合平衡二叉树的定义了,

那么,他为什么这样转啊,他怎么知道这样就可以保持平衡的啊.

其实,在插入一个节点的时候,只有四种情况,会出现不平衡的状态,

看清楚了啊,只有四种情况,这意味着什么,意味着可以直接套用啊

让我列出这四种情况,

第一种:LL型

第二种:RR型

第三种:LR型



第四种:RL型

好了,这就是四种状态,那么为什么叫什么LL,RL,LR之类的呢

我们来看RR型先

这里,我们插入1的时候发现不平衡了,然后把3顺时针旋转了一下,就变平衡了

再看LL型

我们把1逆时针旋转一下,他又平衡了,

好了,聪明的你一定知道什么是LR型了

我们把23逆时针旋转,旋转成1-2-3的样子,再把1顺时针旋转下来,他就又平衡了

思路来说很简单,

难的地方个人觉得是代码会难点

他涉及很多方面知识,(其实是我没测试几组数据,写法也很鱼,不保证对,大家如果测试出错务必评论告诉我)

代码如下

(特别提示一点,如果检测有一个节点的平衡因子变成2或者-2我们才进行旋转,比如一个节点为2,左子树平衡因子为1就LL,为-1就LR旋转,RR和RL类似)

(本咸鱼还没有把删除节点的做出来)

#include <iostream>
using namespace std;
struct avl
{
	int data;
	avl *l;
	avl *r;
	int h;//高度
	int eq;//平衡因子
};
int stop;//停止回溯时候加eq(BF值)的标记


avl* LL(avl *tree)
{
	avl *t=tree->l;
	t->eq=0;
	tree->eq=0;
	t->l->eq=1;
	tree->l=t->r;
	t->r=tree;
	return t;

}
avl* RR(avl *tree)
{
	avl *t=tree->r;
	tree->eq=0;
	t->eq=0;
	t->r->eq=-1;
	tree->r=t->l;
	t->l=tree;
	return t;
}
avl* LR(avl *tree)
{
	avl *t1=tree;
	avl *t2=tree->l;
	avl *t3=tree->l->r;
	t3->eq=0;
	t2->eq=1;
	t1->eq=0;
	//t1->l->eq=-1;
	t1->l=t3->r;
	t2->r=t3->l;
	t3->l=t2;
	t3->r=t1;
	return t3;
}
avl* RL(avl *tree)
{
	avl *t1=tree;
	avl *t2=tree->r;
	avl *t3=tree->r->l;
	t3->eq=0;
	t2->eq=0;
	t1->eq=1;
	
	t1->r=t3->l;
	t2->l=t3->r;
	t3->l=t1;
	t3->r=t2;
	return t3;
}
void addtree(avl **tree,int key)
{
	if (*tree==NULL)
	{          
		(*tree) = (avl*)malloc(sizeof(avl));
		(*tree)->data=key;
		(*tree)->eq=0;
		(*tree)->l=NULL;
		(*tree)->r=NULL;
		(*tree)->h=0;
	} 
	else
	{
		if (key==(*tree)->data)
		{
			cout<<"不允许输入已有项"<<endl;
			return ;
		} 
		else
		{
			if (key<(*tree)->data)
			{
				addtree(&(*tree)->l,key);//递归插入
				if (stop!=0)
				{
					(*tree)->eq+=1;
					if((*tree)->eq==0)
						stop=0;//如果修改到某个数的BF值为0就把标记改为0
				}
				if ((*tree)->l==NULL||(*tree)->r==NULL)
				{
					//左边或者右边没有节点就不用动
				}
				else if ((*tree)->eq==2)//等于二或者等于负二说明这里就不平衡了
				{
					if ((*tree)->l->eq==1)
					{

						//LL
						(*tree)=LL(*tree);
						//
						stop=0;
					}
					if ((*tree)->l->eq==-1)
					{
						//LR
						(*tree)=LR(*tree);
						//
						stop=0;
					}
				} 
				else if((*tree)->eq==-2)
				{
					if ((*tree)->r->eq==1)
					{
						//RL
						(*tree)=RL(*tree);
						//
						stop=0;
					}
					if ((*tree)->r->eq==-1)
					{
						//RR
						(*tree)=RR(*tree);
						//
						stop=0;
					}
				}

			} 
			else
			{
				addtree(&(*tree)->r,key);
				if (stop!=0)
				{
					(*tree)->eq-=1;
					if((*tree)->eq==0)
						stop=0;//如果修改到某个数的BF值为0就把标记改为0
				}
				if ((*tree)->l==NULL||(*tree)->r==NULL)
				{
					//左边或者右边没有节点就不用动
				}
				else if((*tree)->eq==2)//等于二或者等于负二说明这里就不平衡了
				{
					if ((*tree)->l->eq==1)
					{

						//LL
						(*tree)=LL(*tree);
						//
						stop=0;
					}
					if ((*tree)->l->eq==-1)
					{
						//LR
						(*tree)=LR(*tree);
						//
						stop=0;
					}
				} 
				if((*tree)->eq==-2)//等于二或者等于负二说明这里就不平衡了
				{
					if((*tree)->r->eq==1)
					{
						//RL
						(*tree)=RL(*tree);
						//
						stop=0;
					}
					if((*tree)->r->eq==-1)
					{
						//RR
						(*tree)=RR(*tree);
						//
						stop=0;
					}
				}
			}
		}
	}
	if ((*tree)->l==NULL||(*tree)->r==NULL)
	{
		if ((*tree)->l!=NULL||(*tree)->r!=NULL)
		{
			(*tree)->h+=1;
		}
		return;
	}
	(*tree)->h=((*tree)->l->h>=(*tree)->r->h)?((*tree)->l->h+1):((*tree)->r->h+1);//记得调整高度
}
int main()
{
	stop=1;
	avl *tree=NULL;
	addtree(&tree,5);
	stop=1;
	addtree(&tree,4);
	stop=1;
	addtree(&tree,6);
	stop=1;
	addtree(&tree,7);
	stop=1;
	addtree(&tree,1);
	stop=1;
	addtree(&tree,9);
	stop=1;
	addtree(&tree,3);
	stop=1;
	addtree(&tree,8);
	stop=1;
	addtree(&tree,10);
	stop=1;
	addtree(&tree,2);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值