平衡二叉搜索树

全知识整理目录

数据结构整理的目录包括了许多的数据结构相关知识。


目录

概述

旋转的介绍

左单旋转

右单旋转

左右双旋

代码逻辑

结点的创建

左单旋

右单旋

 完整代码


概述

什么是平衡二叉搜索树?

首先需要了解一下什么是二叉搜索树?

左子树都小于根节点,右子树都大于根节点,这样的树就是二叉搜索树。

平衡二叉搜索树就是,不仅要是二叉搜索树,还要是平衡的。每个节点都有一个平衡因子,平衡因子为-1,0,1(平衡因子 = 右子树的高度-左子树的高度)的就是平衡二叉搜索树。

要学习的其实就是,插入和删除的时候,二叉树的平衡因子会变化,那么这就是需要学习和了解的难点重点了。

旋转的介绍

左单旋转

如下图所示,在当前平衡的结点上加上一个5,那么3的平衡因子此时就为2,造成不平衡,所以需要,左旋转(逆时针旋转)。

右单旋转

右单旋转,与做单旋转相反,是指新插入的结点位于,左侧子树,且平衡因子不满足。

下图以原本平衡的树,再插入一个2结点,那么就会有右单旋转,恰好跟左单旋转相反,左右旋转是指结点移动的方向。

左右双旋

如下图如果想要插入37,就会导致平衡因子不符合要求,所以需要做出调整。

是怎么样调整的呢?

动图的调整方式可能比较快,可以看见红色的两条分支是需要调整的,而下面的一条就是左旋,上面的一条就是右旋。后面也有详细分解步骤。

 第一次左旋,之后发现平衡因子还是不满足。继续右旋。

 第二次右旋

 有左右双旋,肯定也有右左双旋,右左双旋就不介绍了,本质上跟左右双旋是一样的。

无论怎么旋,只要记得,从下往上,第一个不满足平衡因子的地方开始旋转,往上继续看,还有多少个不满足的平衡因子就旋转多少次,这样就能够解决了。

代码逻辑

首先需要了解树结点的定义


typedef int ElemType;
typedef struct BSTNode
{
	ElemType key;
	int bf;
	struct BSTNode *lchild,*rchild;
}BSTNode,*BSTree;

结点的创建

typedef enum
{
	EH = 0,
	LH = 1,
	RH = -1	
}bh_t;
 
 
typedef enum
{
	FALSE = 0,
	TRUE = 1
}bool_t;

要实现旋转操作,肯定需要平衡因子发生变化,这里就需要了解插入结点到树中的代码。

插入代码的大概逻辑是:

  1. 树如果为空的话,直接插入什么也不用考虑。
  2. 树不为空,判断是大于根节点还是小于根节点,从而找到插入到左边还是右边。
  3. 然后结点小于父节点的值,就插入到左边,否则插入到右边,相同的数字不予插入。
  4. 再调整平衡因子,平衡因子的调整会根据父节点进行调整,首先插入结点在子树的父节点++,在子节点--,然后再判断父节点的平衡因子(bf),再根据左旋,右旋,左右旋的函数进行调整。
bool_t InsertAVL(BSTree *t,ElemType e,bool_t *taller)
{
	if(NULL == t)    //树为空的情况
		return FALSE;
	if(NULL == *t)    
	{
		*t=(BSTree)malloc(sizeof(BSTNode));
		if(NULL == *t)
			return FALSE;
		(*t)->key=e;
		(*t)->lchild=(*t)->rchild=NULL;
		(*t)->bf=EH;
		*taller=TRUE;
	}
	else
	{
		if(e==(*t)->key)    
		{
			*taller=FALSE;
			return FALSE;
		}
		if(e<(*t)->key)
		{
			if(FALSE == InsertAVL(&((*t)->lchild),e,taller))
				return FALSE; 
			if(*taller)
			{
				switch((*t)->bf)
				{
					case LH:
						LeftBalance(t);
						*taller=FALSE;
						break;
					case EH:
						(*t)->bf=LH;
						*taller=TRUE;
						break;
					case RH:
						(*t)->bf=EH;
						*taller=FALSE;
						break;
				}
			}
		}
		else
		{
			if(FALSE == InsertAVL(&((*t)->rchild),e,taller))
				return FALSE; 
			if(*taller)
			{
				switch((*t)->bf)
				{
					case RH:
						RightBalance(t);
						*taller=FALSE;
						break;
					case EH:
						(*t)->bf=RH;
						*taller=TRUE;
						break;
					case LH:
						(*t)->bf=EH;
						*taller=FALSE;
						break;
				}
			}
		}
	}
	return TRUE;
}

左单旋

void L_Rotate(BSTree *p)
{
	BSTree rc=(*p)->rchild;
	(*p)->rchild=rc->lchild;
	rc->lchild=*p;
	*p=rc;
}
 

右单旋

void R_Rotate(BSTree *p)
{
	BSTree lc=(*p)->lchild;
	(*p)->lchild=lc->rchild;
	lc->rchild=*p;
	*p=lc;
}

 完整代码

#include <stdio.h>
#include <malloc.h>
 
typedef enum
{
	EH = 0,
	LH = 1,
	RH = -1	
}bh_t;
 
 
typedef enum
{
	FALSE = 0,
	TRUE = 1
}bool_t;
 
typedef int ElemType;
 
typedef struct BSTNode
{
	ElemType key;
	int bf;
	struct BSTNode *lchild,*rchild;
}BSTNode,*BSTree;
 
 
void InOrderTraverse(BSTree root)
{
	if(NULL != root)
	{
		InOrderTraverse(root->lchild);
		printf("%d\t",root->key);
		InOrderTraverse(root->rchild);
	}
}
 
 
void PreOrderTraverse(BSTree root)
{
	if(NULL != root)
	{
		printf("%d\t",root->key);
		PreOrderTraverse(root->lchild);
		PreOrderTraverse(root->rchild);
	}
}
 
 
void R_Rotate(BSTree *p)
{
	BSTree lc=(*p)->lchild;
	(*p)->lchild=lc->rchild;
	lc->rchild=*p;
	*p=lc;
}
 
 
void L_Rotate(BSTree *p)
{
	BSTree rc=(*p)->rchild;
	(*p)->rchild=rc->lchild;
	rc->lchild=*p;
	*p=rc;
}
 
 
void LeftBalance(BSTree *T)
{
	BSTree lc=(*T)->lchild;
	BSTree rd = lc->rchild;
	switch(lc->bf)
	{
		case LH:
			(*T)->bf=lc->bf=EH;
			R_Rotate(T);
			break;
		case RH:
			switch(rd->bf)
			{
				case LH: 
					(*T)->bf=RH;
					lc->bf=EH;
					break;
				case EH:
					(*T)->bf=lc->bf=EH;
					break;
				case RH:
					(*T)->bf=EH;
					lc->bf=LH;
					break;
			}
			rd->bf=EH;
			L_Rotate(&((*T)->lchild));
			R_Rotate(T);
			break;
	}
}
 
 
void RightBalance(BSTree *T)
{
	BSTree rc=(*T)->rchild;
	BSTree ld=rc->lchild;
	switch(rc->bf)
	{
		case RH:
			(*T)->bf=rc->bf=EH;
			L_Rotate(T);
			break;
		case LH:
			switch(ld->bf)
			{
				case RH:
					(*T)->bf=LH;
					rc->bf=EH;
					break;
				case EH:
					(*T)->bf=rc->bf=EH;
					break;
				case LH:
					(*T)->bf=EH;
					rc->bf=RH;
					break;
			}
			ld->bf=EH;
			R_Rotate(&((*T)->rchild));
			L_Rotate(T);
			break;
	}
}
 
 
bool_t InsertAVL(BSTree *t,ElemType e,bool_t *taller)
{
	if(NULL == t)
		return FALSE;
	if(NULL == *t)
	{
		*t=(BSTree)malloc(sizeof(BSTNode));
		if(NULL == *t)
			return FALSE;
		(*t)->key=e;
		(*t)->lchild=(*t)->rchild=NULL;
		(*t)->bf=EH;
		*taller=TRUE;
	}
	else
	{
		if(e==(*t)->key)
		{
			*taller=FALSE;
			return FALSE;
		}
		if(e<(*t)->key)
		{
			if(FALSE == InsertAVL(&((*t)->lchild),e,taller))
				return FALSE; 
			if(*taller)
			{
				switch((*t)->bf)
				{
					case LH:
						LeftBalance(t);
						*taller=FALSE;
						break;
					case EH:
						(*t)->bf=LH;
						*taller=TRUE;
						break;
					case RH:
						(*t)->bf=EH;
						*taller=FALSE;
						break;
				}
			}
		}
		else
		{
			if(FALSE == InsertAVL(&((*t)->rchild),e,taller))
				return FALSE; 
			if(*taller)
			{
				switch((*t)->bf)
				{
					case RH:
						RightBalance(t);
						*taller=FALSE;
						break;
					case EH:
						(*t)->bf=RH;
						*taller=TRUE;
						break;
					case LH:
						(*t)->bf=EH;
						*taller=FALSE;
						break;
				}
			}
		}
	}
	return TRUE;
}
 
 
BSTree searchAVL(BSTree t,ElemType key)
{
	BSTree p=t;
	while(p)
	{
		if(p->key==key)
			return p;
		else if(p->key<key)
			p=p->rchild;
		else
			p=p->lchild;
	}
	return p;
}
 
static void destroy(BSTree *t)
{
	if(NULL != *t)
	{
		destroy(&((*t)->lchild));
		destroy(&((*t)->rchild));
		free(*t);
		*t = NULL;
	}
	return;
}
void destroyAVL(BSTree root)
{
	if(NULL != root)
	{
		destroy(&root);
	}
	return;
}
 
int main(int argc,char *argv[])
{
	BSTree root=NULL,r;
	bool_t taller=FALSE;
	int array[]={13,24,37,90,53};
	int i = 0;
	for(i=0;i<5;i++)
		InsertAVL(&root,array[i],&taller);
	printf("inorder traverse\n");
	InOrderTraverse(root);
 
	printf("\npreorder traverse\n");
	PreOrderTraverse(root);
 
	printf("\nsearch key\n");
	r=searchAVL(root,37);
	if(r)
	{
		printf("%d\n",r->key);
	}
	else
	{
		printf("not find!\n");
	}
	destroyAVL(root);
	root = NULL;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ybbgrain

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值