平衡二叉排序树

平衡二叉排序树

平衡二叉排序树是在插入函数中处理

/* 若在平衡的二叉排序树T中不存在和e有相同关键字的结点,则插入一个 */
/* 数据元素为e的新结点并返回1,否则返回0.若因插入而使二叉排序树 */
/* 失去平衡,则作平衡旋转处理,布尔变量taller反映T长高与否 */
Status InsertAVL(BiTree* T, int e, Status *taller)
{
	if (!*T) 
	{/* 插入新结点,树"长高",置taller为TRUE */
		*T = (BiTree)malloc(sizeof(BiTNode));
		(*T)->data = e;
		(*T)->lchild = (*T)->rchild = NULL;
		(*T)->bf = EH;
		*taller = TRUE;
	}
	else
	{
		if (e == (*T)->data)
		{	/* 树中已存在和e有相同关键字的结点则不再插入 */
			*taller = FALSE;
			return FALSE;
		}
		if (e < (*T)->data)
		{/* 应继续在T的左子树中进行搜索 */
			if (!InsertAVL(&(*T)->lchild, e, taller)) /* 未插入 */
				return FALSE;
			if (*taller) /* 已插入到T的左子树中且左子树"长高" */
			{
				switch ((*T)->bf) /* 检查T的平衡度 */
				{
					case LH: /* 原本左子树比右子树高,需要作左平衡处理 */
						LeftBalance(T);
						*taller = FALSE;
						break;
					case EH: /* 原本左右子树等高,现在因左子树增高而树增高 */
						(*T)->bf = LH;
						*taller = TRUE;
						break;
					case RH:/* 原本右子树比左子树高,现在左、右子树等高 */
						(*T)->bf = EH;
						*taller = FALSE;
						break;
				}
			}
		}
		else
		{/* 应继续在T的右子树中进行搜索 */
			if (!InsertAVL(&(*T)->rchild, e, taller)) /* 未插入 */
				return FALSE;
			if (*taller) /* 已插入到T的左子树中且左子树"长高" */
			{
				switch ((*T)->bf) /* 检查T的平衡度 */
				{
				case LH: /* 原本左子树比右子树高,现在左、右子树等高 */
					(*T)->bf = EH;
					*taller = FALSE;
					break;
				case EH:	/* 原本左右子树等高,现在因右子树增高而树增高 */
					(*T)->bf = LH;
					*taller = TRUE;
					break;
				case RH:/* 原本右子树比左子树高,需要作右平衡(左旋转)处理 */
					RightBalance(T);
					*taller = FALSE;
					break;
				}
			}
		}
	}
	return TRUE;
}
当传入的T的第一层为NULL,即为整颗树为空时,对该结点进行插入操作,并修改taller变量为TRUE,最后该函数结束返回一个TRUE;表示插入成功

或者当传入的T的第一层为不为NULL,即为整颗树不为空时,
则有三种情况:

1、当要插入的结点的data值e等于T的data值时;
taller值为FALSE,返回一个FALSE值,表示插入失败。

2、当要插入的结点的data值e小于T的data值时;
递归调用该函数,并传入T的左子树,e,taller;
当递归的返回值为FALSE时;
即插入失败,此时需要继续返回FASLE,表示插入失败,直到递归结束。

或者当递归的返回值为TRUE时,即插入成功时;
继续往下执行,第一次执行时,是插入结点的上一级;因为当插入成功后taller值为TRUE,即树增高,需要做相应处理;
此时分三种情况:

 第一,当当前结点的bf值为1,即原本左子树比右子树高,又因为插入结点插入在当前结点的左子树,此时需要做左平衡处理,调用左平衡处理函数并将taller值修改为FALSE,因为左平衡处理后树就平衡了,即不需要再处理了,所以taller为FALSE。
 
 第二,当当前结点的bf值为0,即原本左子树和右子树等高,又因为插入结点插入在当前结点的左子树,此时需要将T的bf值修改为1,因为插入结点后因左子树增高而树增高;taller值为TRUE,即上一层还需要继续处理。

第三,当当前结点的bf值为-1,即原本右子树比左子树高,又因为插入结点插入在当前结点的左子树,此时需要将T的bf值修改为0,因为插入结点后因左右子树登高;taller值为FALSE,即其它层不需要处理;因为只是在原本的基础上再加一个左子树,所以对其它层没有影响。

3、当要插入的结点的data值e大于T的data值时;
递归调用该函数,并传入T的左子树,e,taller;
当递归的返回值为FALSE时;
即插入失败,此时需要继续返回FASLE,表示插入失败,直到递归结束。

或者当递归的返回值为TRUE时,即插入成功时;
继续往下执行,第一次执行时,是插入结点的上一级;因为当插入成功后taller值为TRUE,即树增高,需要做相应处理;
此时分三种情况:

 第一,当当前结点的bf值为1,即原本左子树比右子树高,又因为插入结点插入在当前结点的右子树,此时需要将T的bf值修改为0,因为插入结点后因左右子树登高;taller值为FALSE,即其它层不需要处理;因为只是在原本的基础上再加一个右子树,所以对其它层没有影响。
 
 第二,当当前结点的bf值为0,即原本左子树和右子树等高,又因为插入结点插入在当前结点的右子树,此时需要将T的bf值修改为-1,因为插入结点后因右子树增高而树增高;taller值为TRUE,即上一层还需要继续处理。

第三,当当前结点的bf值为-1,即原本右子树比左子树高,又因为插入结点插入在当前结点的右子树,此时需要做右平衡处理,调用右平衡处理函数并将taller值修改为FALSE,因为右平衡处理后树就平衡了,即不需要再处理了,所以taller为FALSE。

左平衡函数:

/*对以指针T所指结点为根的二叉树作左平衡旋转处理*/
/*本算法结束时,指针T指向新的根节点*/
void LeftBalance(BiTree* T) 
{
	BiTree L, Lr;
	L = (*T)->lchild; /*L指向T的左子树根节点*/
	switch (L->bf)
	{/* 检查T的左子树的平衡度,并作相应平衡处理 */
		case LH: /* 新结点插入在T的左孩子的左子树上,要作单右旋处理 */
			(*T)->bf = L->bf = EH; 
			R_Rotate(T);
			break;
		case RH: /* 新结点插入在T的左孩子的右子树上,要作双旋处理 */
			Lr = L->rchild; /* Lr指向T的左孩子的右子树根 */
			switch (Lr->bf) /* 修改T及其左孩子的平衡因子 */
			{
				case LH:
					(*T)->bf = RH;
					L->bf = EH;
					break;
				case EH:
					(*T)->bf = L->bf = EH;
					 
					break;
				case RH:
					(*T)->bf = EH;
					L->bf = LH;
					break;
			}
			Lr->bf = EH;
			L_Rotate(&(*T)->lchild);/* 对T的左子树作左旋平衡处理 */
			R_Rotate(T); /* 对T作右旋平衡处理 */
			break;
	}


}
当需要左平衡的时候,该T的bf值为1;
L为T的左子树,因为需要做左平衡处理时,该树的层序至少为3;
L的bf值不可能为0;即L的左右子树的深度差为1;

当L的bf值为1时,即新插入结点在L的左子树上或为L的左子树;

	此时满足右旋转的条件;直接将T和L的bf值都修改为0,再调用右旋转函数将T作为参数传入。

当L的bf值为-1时,即插入结点在L的右子树上或为L的右子树;

	此时不满足右旋转条件,需要将L进行左旋转再将T右旋转且将Lr的bf值修改为0,因为Lr最后会成为根节点,T指向Lr;并将T和L的bf值进行相应的修改。
	Lr为L的右子树,
	
	当Lr的bf值为1时,说明新插入结点为Lr的左子树,
	此时需要将T的bf值改为-1,L的bf值为0;
	在双旋转后,因为是左平衡,所以新插入结点N的data值<T的data值;又因为N为Lr的左子树,所以N的data值<Lr的data值;即N<T且N<Lr;所以T的左子树为空值,所以T的bf值为-1
	因为Lr为L的右子树,Lr的所有结点都比L大,所以N的data值>L的data值,又因为N为Lr的左子树,所以N的data值<Lr的data值,即L<N<Lr,所以L的右子树为新结点N,所以L的bf值为0;
	
	当Lr的bf值为0时,说明新插入结点为L的右子树,即Lr为新结点,Lr的左右子树为空;
	在双旋转后,因为Lr不存在左右结点,所以T和L的bf值都为0;

	当Lr的bf值为-1时,说明新插入结点为Lr的右子树,
	此时需要将T的bf值改为0,L的bf值为1;
	在双旋转后,因为是左平衡,所以新插入结点N的data值<T的data值;又因为N为Lr的右子树,所以N的data值>Lr的data值;即Lr<N<T;所以T的左子树为新结点N,所以T的bf值为0
	因为Lr为L的右子树,Lr的所有结点都比L大,所以N的data值>L的data值,又因为N为Lr的右子树,所以N的data值>Lr的data值,即L<N且Lr<N,所以L的右子树为空,所以L的bf值为1;

右平衡函数:

/*对以指针T所指结点为根的二叉树作左平衡旋转处理*/
/*本算法结束时,指针T指向新的根节点*/
void RightBalance(BiTree* T)
{
	BiTree R, Rl;
	R = (*T)->rchild; /*L指向T的右子树根节点*/
	switch (R->bf)
	{/* 检查T的右子树的平衡度,并作相应平衡处理 */
		case LH: /* 新结点插入在T的右孩子的左子树上,要作双旋处理 */
		
			Rl = R->lchild; /* Lr指向T的右孩子的左子树根 */
			switch (Rl->bf) /* 修改T及其右孩子的平衡因子 */
			{
				case LH:
					(*T)->bf = EH;
					R->bf = RH;
					break;
				case EH:
					(*T)->bf = R->bf = EH;

					break;
				case RH:
					(*T)->bf = LH;
					R->bf = EH;
					break;
			}
			Rl->bf = EH;
			R_Rotate(&(*T)->rchild);/* 对T的右子树作右旋平衡处理 */
			L_Rotate(T); /* 对T作左旋平衡处理 */
			break;
	

		case RH: /* 新结点插入在T的右孩子的右子树上,要作单左旋处理 */
			(*T)->bf = R->bf = EH;
			L_Rotate(T);
			break;
	}
}
当需要右平衡的时候,该T的bf值为-1;
R为T的右子树,因为需要做右平衡处理时,该树的层序至少为3;
R的bf值不可能为0;即R的左右子树的深度差为1;

当R的bf值为1时,即新插入结点在R的左子树上或为R的左子树;

		此时不满足左旋转条件,需要将R进行右旋转再将T左旋转且将Rl的bf值修改为0,因为Rl最后会成为根节点,T指向Rl;并将T和R的bf值进行相应的修改。
	Rl为R的左子树,
	
	当Rl的bf值为1时,说明新插入结点为Rl的左子树,
	此时需要将T的bf值改为0,R的bf值为-1;
	在双旋转后,因为是右平衡,所以新插入结点N的data值>T的data值;又因为N为Rl的左子树,所以N的data值<Rl的data值;即T<N<Rl;所以T的右子树为新结点N,所以T的bf值为0
	因为Rl为R的左子树,Rl的所有结点都比L小,所以N的data值<R的data值,又因为N为Rl的左子树,所以N的data值<Lr的data值,即N<Rl且N<R,所以R的左子树为空,所以R的bf值为-1;
	
	当Rl的bf值为0时,说明新插入结点为R的左子树,即Rl为新结点,Rl的左右子树为空;
	在双旋转后,因为Rl不存在左右结点,所以T和R的bf值都为0;

	当Rl的bf值为-1时,说明新插入结点为Rl的右子树,
	此时需要将T的bf值改为1,L的bf值为0;
	在双旋转后,因为是右平衡,所以新插入结点N的data值>T的data值;又因为N为Rl的右子树,所以N的data值>Rl的data值;即Rl<N且T<N;所以T的右子树为空,所以T的bf值为1
	因为Rl为R的左子树,Rl的所有结点都比R小,所以N的data值<R的data值,又因为N为Rl的右子树,所以N的data值>Rl的data值,即Rl<N<R,所以R的左子树为新结点N,所以R的bf值为0;	

当R的bf值为-1时,即插入结点在R的右子树上或为R的右子树;
此时满足左旋转的条件;直接将T和R的bf值都修改为0,再调用左旋转函数将T作为参数传入。

左旋转函数:

void L_Rotate(BiTree *p)
{
	BiTree R;
	R = (*p)->rchild; /*L指向p的右子树根结点*/
	(*p)->rchild = R->lchild;/*将p的右子树指向 p的左子树的右子树*/
	R->lchild = (*p);/*p的右子树的右子树指向P*/
	(*p) = R; /*p指向R*/
}

将T的左子树L的右子树置为T的左子树,将T置为L的右子树,T指向L,表示L为根结点;
若L的右子树不存在则T不存在左子树;直接将T置为L的右子树;

右旋转函数:

void R_Rotate(BiTree *p) 
{
	BiTree L;
	L = (*p)->lchild; /*L指向p的左子树根节点*/
	(*p)->lchild = L->rchild;/*将p的左子树指向 p的左子树的右子树*/
	L->rchild = (*p);/*p的左子树的右子树指向P*/
	(*p) = L; /*p指向L*/
}

将T的右子树R的左子树置为T的右子树,将T置为R的左子树,T指向R,表示R为根结点;
若R的左子树不存在则T不存在右子树;直接将T置为R的左子树;

在插入时,左平衡调用的是单右旋转,或者是双旋,左旋转后右旋转;
右平衡是单左旋转,或者是双旋。又旋后左旋``

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值