AVL树的插入与删除

本来之前已经发了AVL树的插入,结果续写AVL树的删除时发现之前写的AVL插入有bug,于是乎将其删除了。折腾了一周多,终于将AVL树搞定了。。。不容易啊

//AVLTree.h

#ifndef _AVLTREE_H_
#define _AVLTREE_H_
#include <stdlib.h>

typedef int Element;

typedef struct _AVLTreeNode
{
	Element Data;
	int		BF;							//平衡因子
	struct _AVLTreeNode *Parent;		//指向双亲节点,用于回溯,也可以不含此指针,而通过栈来保存插入路径
	struct _AVLTreeNode *LChild;
	struct _AVLTreeNode *RChild;
}AVLTreeNode;

typedef AVLTreeNode *AVLTree;

void AVLInit(AVLTree *tree);
bool AVLInsert(AVLTree *tree, Element v);
AVLTreeNode *CreateNode(Element v);
void RotateL(AVLTree *AVLTreeRoot);
void RotateR(AVLTree *AVLTreeRoot);
void RotateLR(AVLTree *AVLTreeRoot);
void RotateRL(AVLTree *AVLTreeRoot);
bool AVLDelete(AVLTree *tree, Element v);

#endif // _AVLTREE_H_

//AVLTree.c

#include "AVLTree.h"


void AVLInit(AVLTree *tree)
{
	*tree = NULL;
}

AVLTreeNode *CreateNode(Element v)
{
	AVLTreeNode *q = (AVLTreeNode *)malloc(sizeof(AVLTreeNode));
	if( NULL == q )
		return NULL;

	q->Data = v;
	q->BF = 0;
	q->Parent = q->LChild = q->RChild = NULL;
	return q;
}

bool AVLInsert(AVLTree *tree, Element v)
{
	if( NULL == *tree )
	{
		AVLTreeNode *q = CreateNode(v);
		if( NULL == q )
			return false;

		*tree = q;
	}
	else
	{
		AVLTreeNode *s = NULL;		//用于存储最小不平衡子树的双亲节点
		AVLTreeNode *n = *tree;
		AVLTreeNode *p = NULL;		//用于记录插入路径
		while (NULL != n)			//循环用于寻找新节点应该插入的位置
		{
			if( v > n->Data )
			{
				p = n;				
				n = n->RChild;
			}
			else if( v < n->Data )
			{
				p = n;
				n = n->LChild;
			}
			else					//不能插入相同值
				return false;
		}
		n = CreateNode(v);
		if( NULL == n )
			return false;

		if( v > p->Data )
			p->RChild = n;			//挂接新节点
		else
			p->LChild = n;
		n->Parent = p;				//记录双亲节点,便于回溯调整平衡因子

		while (NULL != p)			//从最新插入的节点开始向上回溯以调整平衡因子
		{
			if( p->LChild == n )	
				p->BF++;
			else
				p->BF--;

			if( -1 == p->BF || 1== p->BF )		//不知祖双亲节点的情况,回溯
			{
				n = p;							
				p = p->Parent;
			}
			else if( 0 == p->BF )				//双亲节点是平衡的则无需回溯
				break;
			else								//不平衡则立刻旋转
			{
				s = p->Parent;					
				if( p->BF > 0 && n->BF > 0 )		
					RotateR(&p);				//BF同号且大于0,右旋转以降低左树高
				else if( p->BF < 0 && n->BF < 0 )
					RotateL(&p);
				else if( p->BF > 0 && n->BF < 0 )
					RotateLR(&p);				//BF异号,最小不平衡子树BF大于0,先左再右旋转
				else
					RotateRL(&p);

				if( NULL == s )					//s为NULL说明原来的p(即传入旋转函数时的p)为整棵树的根,p不为整颗树的根在旋转函数中处理了
					*tree = p;					//将新根作为整棵树的根
				break;							//修改平衡后无需继续回溯
			}
		}
	}
	return true;								//树平衡
}

void RotateL(AVLTree *AVLTreeRoot)
{
	AVLTreeNode *GrandParent = (*AVLTreeRoot)->Parent;	//最小不平衡子树根的双亲节点
	AVLTreeNode *Parent = (*AVLTreeRoot)->RChild;		//旋转完成之后的树根;
	AVLTreeNode *SubLeft = *AVLTreeRoot;				//旋转完成之后的左子树;
	SubLeft->RChild = Parent->LChild;					//Parent节点可能存在左子树,先保存
	if( NULL != Parent->LChild )						//如果确实存在
		Parent->LChild->Parent = SubLeft;				//修改其双亲节点
	Parent->LChild = SubLeft;							//左旋转
	SubLeft->Parent = Parent;							//修改双亲点
	Parent->BF = SubLeft->BF = 0;						//修改平衡因子
	if( NULL != GrandParent && GrandParent->LChild == *AVLTreeRoot )			//将最小不平衡子树的双亲节点与旋转完成后的树根连接起来
		GrandParent->LChild = Parent;
	if( NULL != GrandParent && GrandParent->RChild == *AVLTreeRoot )
		GrandParent->RChild = Parent;
	*AVLTreeRoot = Parent;								//更改树根
	Parent->Parent = GrandParent;						//新树根的双亲节点
}

void RotateR(AVLTree *AVLTreeRoot)
{
	AVLTreeNode *GrandParent = (*AVLTreeRoot)->Parent;	
	AVLTreeNode *Parent = (*AVLTreeRoot)->LChild;
	AVLTreeNode *SubRight = *AVLTreeRoot;
	SubRight->LChild = Parent->RChild;
	if( NULL != Parent->RChild )
		Parent->RChild->Parent = SubRight;
	Parent->RChild = SubRight;
	SubRight->Parent = Parent;
	Parent->BF = SubRight->BF = 0;
	if( NULL != GrandParent && GrandParent->LChild == *AVLTreeRoot )			
		GrandParent->LChild = Parent;
	if( NULL != GrandParent && GrandParent->RChild == *AVLTreeRoot )
		GrandParent->RChild = Parent;
	*AVLTreeRoot = Parent;
	Parent->Parent = GrandParent;
}

void RotateLR(AVLTree *AVLTreeRoot)
{
	AVLTreeNode *GrandParent = (*AVLTreeRoot)->Parent;
	AVLTreeNode *SubRight = *AVLTreeRoot;
	AVLTreeNode *SubLeft = (*AVLTreeRoot)->LChild;
	AVLTreeNode *Parent = SubLeft->RChild; 
	SubLeft->RChild = Parent->LChild;				//保存Parent可能存在的左子树
	if( NULL != Parent->LChild )					//如果确实存在
		Parent->LChild->Parent = SubLeft;			//修改其双亲节点
	Parent->LChild = SubLeft;						//左旋转
	SubLeft->Parent = Parent;
	SubRight->LChild = Parent->RChild;				//保存Parent可能存在的右子树
	if( NULL != Parent->RChild )					//确实存在
		Parent->RChild->Parent = SubRight;			//修改其双亲节点
	Parent->RChild = SubRight;						//右旋转
	SubRight->Parent = Parent;
	if( 0 == Parent->BF )							//查看Parent旋转之前的子树情况,其BF为0时为前篇博客所诉的情况1
		SubRight->BF = SubLeft->BF = 0;				//Parent已平衡,无需调整
	else if( 1 == Parent->BF )						//情况2且Parent旋转之前仅有左子树
	{
		SubLeft->BF = 0;
		SubRight->BF = -1;
		Parent->BF = 0;
	}
	else											//情况2且Parent旋转之前仅有右子树
	{
		SubLeft->BF = -1;
		SubRight->BF = 0;
		Parent->BF = 0;
	}
	if( NULL != GrandParent && GrandParent->LChild == *AVLTreeRoot )			//将最小不平衡子树的双亲节点与旋转完成后的树根连接起来
		GrandParent->LChild = Parent;
	if( NULL != GrandParent && GrandParent->RChild == *AVLTreeRoot )
		GrandParent->RChild = Parent;
	*AVLTreeRoot = Parent;							//更改树根
	Parent->Parent = GrandParent;
}

void RotateRL(AVLTree *AVLTreeRoot)
{
	AVLTreeNode *GrandParent = (*AVLTreeRoot)->Parent;
	AVLTreeNode *SubLeft = *AVLTreeRoot;
	AVLTreeNode *SubRight = SubLeft->RChild;
	AVLTreeNode *Parent = SubRight->LChild;
	SubRight->LChild = Parent->RChild;
	if( NULL != Parent->RChild )
		Parent->RChild->Parent = SubRight;
	Parent->RChild = SubRight;
	SubRight->Parent = Parent;
	SubLeft->RChild = Parent->LChild;
	if( NULL != Parent->LChild )
		Parent->LChild->Parent = SubLeft;
	Parent->LChild = SubLeft;
	SubLeft->Parent = Parent;
	if( 0 == Parent->BF )
		SubLeft->BF = SubRight->BF = 0;
	else if( 1 == Parent->BF )
	{
		SubLeft->BF = 0;
		SubRight->BF = 1;
		Parent->BF = 0;
	}
	else
	{
		SubLeft->BF = 1;
		SubRight->BF = 0;
		Parent->BF = 0;
	}
	if( NULL != GrandParent && GrandParent->LChild == *AVLTreeRoot )			
		GrandParent->LChild = Parent;
	if( NULL != GrandParent && GrandParent->RChild == *AVLTreeRoot )
		GrandParent->RChild = Parent;
	*AVLTreeRoot = Parent;
	Parent->Parent = GrandParent;
}


bool AVLDelete(AVLTree *tree, Element v)
{
	AVLTreeNode *p = *tree;		//意图删除节点
	AVLTreeNode *q = NULL;		//意图删除节点的子节点
	AVLTreeNode *pp = NULL;		//意图删除节点的双亲节点
	AVLTreeNode *s = NULL;		//用于存储最小不平衡子树的双亲节点
	int flag = 0;				//左右子树标记,此标记为必须的,用于避免意图删除节点的双亲的另一子树为NULL且意图删除节点的子树也为NULL时影响判断
	while (NULL != p)
	{
		if( p->Data == v )
			break;
		else if( p->Data > v )
			p = p->LChild;
		else
			p = p->RChild;	
	}

	if( NULL == p )			//节点不存在或树为空
		return false;

	if( NULL != p->LChild && NULL != p->RChild )	//节点存在左右子树,转化为最多存在一个子树的情况再删除,此处转化为删除p右子树中最小节点
	{
		q = p->RChild;
		while (NULL != q->LChild)
			q = q->LChild;
		p->Data = q->Data;							
		p = q;										
	}
	//最多存在一个子树
	pp = p->Parent;
	if( NULL == pp )							//删除只有一个节点的AVL树(节点存在但其双亲节点不存在,意图删除节点必是树根)
	{
		free(p);
		*(tree) = NULL;
		return true;
	}
	//寻找可能存在节点的子树q以备以后挂接
	if( NULL == p->LChild )
		q = p->RChild;							
	else
		q = p->LChild;

	if( pp->LChild == p)						//意图删除的节点为其双亲节点的左子树
	{
		pp->LChild = q;							//用其可能存在的子树将其替换
		flag = 1;
	}
	else
	{
		pp->RChild = q;
		flag = -1;
	}

	if( NULL != q )								//修改其子树的双亲节点
		q->Parent = pp;
	free(p);									//释放

	while (NULL != pp)							//回溯
	{
		if( q == pp->LChild && 1 == flag )		//被删的节点在其双亲节点的左子树
			pp->BF--;
		if( q == pp->RChild && -1 == flag )
			pp->BF++;
		if( 1 == pp->BF || -1 == pp->BF )		//只是双亲节点的一边的子树缩短了一点,其所在树高度无变化,整体树依旧平衡
			break;
		else if( 0 == pp->BF )					//双亲节点树高度变化,继续回溯查看上层情况,查看是否影响上层平衡
		{
			q = pp;
			pp = pp->Parent;
			if( NULL != pp && pp->LChild == q)	//从双亲左子树回溯
				flag = 1;
			else
				flag = -1;
		}
		else									//双亲较低子树高度降低,树本身已不平衡
		{
			s = pp->Parent;
			if( pp->BF > 0 )					//令q指向双亲的较高子树
				q = pp->LChild;
			else
				q = pp->RChild;

			if( pp->BF > 0 )
			{
				if( q->BF > 0 )					//右单旋转
				{
					RotateR(&pp);
				}
				else if( q->BF = 0 )			//右单旋转,且需要额外更改平衡因子
				{
					RotateR(&pp);
					pp->BF = -1;
					q->BF = 1;
				}
				else							//先左后右旋转
				{
					RotateLR(&pp);
				}
			}else
			{
				if( q->BF > 0 )					//先右后左旋转
				{
					RotateRL(&pp);
				}
				else if( q->BF = 0 )				//左单旋转,且需额外更改平衡因子
				{
					RotateL(&pp);
					pp->BF = 1;
					q->BF = -1;
				}
				else							//左单旋转
				{
					RotateL(&pp);
				}
			
			}
			if( NULL == s )					//s为NULL说明原来的p(即传入旋转函数时的p)为整棵树的根,p不为整颗树的根在旋转函数中处理了
				*tree = pp;					//将新根作为整棵树的根		
		}
	}
	return true;
}

//main.c

#include "AVLTree.h"
#include "stdio.h"

int main()
{//	Element a[] = {100, 10, 66, 87, 90, 60, 32, 55, 0, 99};
//	Element a[] = {0, 1, 2 ,3, 4, 5, 6, 7, 8, 9};
//	Element a[] = { 99, 88,77, 66, 55, 44, 33, 22 };
	Element a[] = {60, 40, 70, 30, 50, 65, 80, 20, 35, 45, 55, 68, 75, 90, 15, 43, 48, 58, 85, 42};
	int t = sizeof(a) / sizeof(Element);
	AVLTree tree;
	bool ret = false;
	AVLInit(&tree);
	for(int i=0; i<t; i++)
		AVLInsert(&tree, a[i]);

	ret = AVLDelete(&tree, 20);
	if( false == ret ) 
		printf("节点不存在或树为空\n");
	system("pause");
	return 1; 
}





 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值