重学数据结构008——AVL树

 

    之前学习了二叉查找树的及相关操作。二叉查找树的大部分主要操作的复杂度都是O(logN)量级的。现在考虑这样一种情况:通过集合{3,2,4,1,0,-1,-2,-3,-4,-4}中的元素来构建二叉查找树,得到的树如图所示:

image

    如果现在我们需要查找元素-4,那么时间复杂度还是是O(logN)吗?有个更加极端的例子,假设数据集是{6,5,3,1,0,-1,-2,-3,-4,-4}呢?再去查找元素-4,其复杂度已经是O(N)了。也就是说,二叉查找树的查找优势完全不复存在了。在这样的情况下,以前的牛人们又想出了别的办法:让二叉查找树除了满足现有条件外,添加平衡条件,形成平衡二叉树。AVL树是其中一种典型的平衡二叉树,

    AVL树是带有平衡条件的二叉查找树。在满足所有二叉查找树条件下,还加入了平衡条件:AVl树的每个节点的左右子树的高度差必须<=1。 在我使用的这本教材中,定义空树的高度为-1,一个节点的树的高度定义为0。

   为了满足平衡条件,AVL树的基本操作一般涉及运作同在不平衡的二叉查找树所运作的同样的算法。但是要进行预先或随后做一次或多次所谓的"AVL旋转"。

涉及到的几种情况如下图所示:

Tree_Rebalancing

 

    AVL树的基本操作代码如下:

#include <stdio.h>
#include <stdlib.h>

#define MAX(X,Y) ((X > Y) ? X : Y)

typedef int ElementType;
typedef struct AvlNode *Position;
typedef struct AvlNode *AvlTree;

/************************************************************************/
/* Avl树的数据结构定义以及节本操作定义                                  */
/************************************************************************/

struct AvlNode 
{
	ElementType Element;
	int Height;
	AvlTree Left,Right;
};


AvlTree MakeEmpty(AvlTree T);				                 /*清空Avl树*/

Position Find(ElementType X, AvlTree T);   	   /*在Avl树中查找指定的元素*/

Position FindMax(AvlTree T);					 /*在Avl树中查找最大元素*/

Position FindMin(AvlTree T);					 /*在Avl树中查找最小元素*/

AvlTree Insert(ElementType X, AvlTree T);		 /*在Avl树中插入指定元素*/

AvlTree Delete(ElementType X, AvlTree T);		 /*在Avl树中删除指定元素*/

ElementType Retrieve(Position P);			      /*获取指定节点的元素值*/

int Height(Position P);							  /*获得指定节点的高度值*/

Position SingleRotateWithLeft(Position P);					  /*单右旋转*/

Position SingleRotateWithRight(Position P);					  /*单左旋转*/

Position DoubleRotateWithLeft(Position P);					/*双左右旋转*/

Position DoubleRotateWithRight(Position P);					/*双右左旋转*/

int main(void) 
{

	return 0;
}

/************************************************************************/
/* 清空AVL树的操作与清空普通二叉树相同                                  */
/************************************************************************/
AvlTree MakeEmpty(AvlTree T) 
{
	if (!T)
	{
		MakeEmpty(T->Left);
		MakeEmpty(T->Right);
		free(T);
	}
	return NULL;
}

/************************************************************************/
/*在Avl树中查找指定的元素,与二叉查找树的操作相同                        */
/************************************************************************/
Position Find(ElementType X, AvlTree T)
{
	if (T == NULL)
	{
		return NULL;
	} 
	else
	{
		if (X < T->Element)
		{
			return Find(X,T->Left);
		}
		else if(X > T->Element)
		{
			return Find(X, T->Right);
		}
		else
		{
			return T;
		}
	}
}

/************************************************************************/
/* 在Avl树中查找最大值(递归写法)                                        */
/************************************************************************/
Position FindMax(AvlTree T)
{
	if (T == NULL)
	{
		return NULL;
	} 
	else
	{
		if (T->Right == NULL)
		{
			return NULL;
		} 
		else
		{
			return FindMax(T->Right);
		}
	}
}


/************************************************************************/
/* 在Avl树中查找最小值(非递归写法)                                      */
/************************************************************************/
Position FindMin(AvlTree T)
{
	if (T == NULL)
	{
		return NULL;
	}
	else
	{
		while (T->Left != NULL)
		{
			T = T->Left;
		}
		return T;
	}
}

/************************************************************************/
/* 返回指定节点的高度信息                                               */
/************************************************************************/
int Height(Position P) 
{
	if (P == NULL)
	{
		return -1;
	}
	else
	{
		return P->Height;
	}
}

/************************************************************************/
/* 单旋转:右旋转                                                       */
/* 使用条件:这个函数只适合当P有左子树时调用;                          */
/* 作用:在P和其左子树根节点之间执行一次单右旋转						*/
/************************************************************************/
Position SingleRotateWithLeft(Position P)
{
	Position LChild = P->Left;
	P->Left = LChild->Right;		   /*将P的左孩子设置成LChild的右孩子*/
	LChild->Right = P;

	P->Height = MAX(Height(P->Left),Height(P->Right)) + 1;/*更新高度信息*/
	LChild->Height = MAX(Height(LChild->Left),P->Height) + 1;

	return LChild;											/*新的根节点*/	
}


/************************************************************************/
/* 单旋转:左旋转                                                       */
/* 使用条件:这个函数只适合当P有右子树时调用;							*/
/* 作用:在P和其右子树根节点之间执行一次单左旋转						*/
/************************************************************************/
Position SingleRotateWithRight(Position P)
{
	Position RChild = P->Right;		   /*将P的右孩子设置成RChild的右孩子*/
	P->Right = RChild->Left;								
	RChild->Left = P;

	P->Height = MAX(Height(P->Left),Height(P->Right)) + 1;/*更新高度信息*/
	RChild->Height = MAX(Height(RChild->Right),P->Height) + 1;
	return RChild;											/*新的根节点*/
}


/************************************************************************/
/* 双旋转:左右旋转                                                     */
/* 使用条件:适合于当P有左孩子,而左孩子有右孩子                        */
/* 作用:*/
/************************************************************************/
Position DoubleRotateWithLeft(Position P)
{
	P->Left = SingleRotateWithRight(P->Left);			  /*先进行左旋转*/
	return SingleRotateWithLeft(P);						  /*再进行又旋转*/
}


/************************************************************************/
/* 双旋转:右左旋转                                                     */
/* 使用条件:适合于当P有右孩子,而右孩子有左孩子                        */
/* 作用:*/
/************************************************************************/
Position DoubleRotateWithRight(Position P)
{
	P->Right = SingleRotateWithLeft(P->Right);			  /*先进行右旋转*/
	return SingleRotateWithRight(P);				      /*再进行左旋转*/
}

/************************************************************************/
/* AVL树插入操作                                                        */
/************************************************************************/
AvlTree Insert(ElementType X, AvlTree T)
{
	/*如果T是一棵空树,那么创建一个节点作为树的根节点*/
	if (T == NULL)
	{
		T = malloc(sizeof(struct AvlNode));
		if(T == NULL)
		{
			fprintf(stderr,"Out of space!");
		}
		else
		{
			T->Element = X;
			T->Left = NULL;
			T->Right = NULL;
			T->Height = 0;
		}
	}else
	{
		if (X < T->Element)
		{
			T->Left = Insert(X,T->Left);
			/*判断是否打破了破了平衡条件*/
			if (Height(T->Left) - Height(T->Right) == 2)
			{
				/*判断是四种情况中的哪一种情况*/
				if (X < T->Left->Element)
				{
					T = SingleRotateWithLeft(T);
				}
				else if (X > T->Left->Element)
				{
					T = DoubleRotateWithLeft(T);
				}
			}
		}
		else if (X > T->Element)
		{
			T->Right = Insert(X,T->Right);
			if (Height(T->Right) - Height(T->Left) == 2)
			{
				if(X < T->Right->Element)
				{
					T = DoubleRotateWithRight(T);
				}
				else if (X > T->Right->Element)
				{
					T = SingleRotateWithRight(T);
				}
			}
		}
		else
		{
			/*元素已经存在于AVL树中,因此不需要再做别的工作*/
		}

		/*更新数的高度信息*/
		T->Height = MAX(Height(T->Left),Height(T->Right)) + 1;


	
	}
	return T;
}


 

上述AVL旋转的示意图来自维基百科:AVL树

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值