《大话数据结构》第8章 查找--PART2

                 《大话数据结构》第8章 查找--PART2

目录

5.平衡二叉树

5.1 基础知识

5.2 平衡二叉树构建的基本思想

5.3 平衡二叉树实现算法(hard==)


5.平衡二叉树

5.1 基础知识

    平衡二叉树(Self-Balancing Binary Search Tree或Height-Balanced Binary Search Tree)又称AVL树,是一种二叉排序树,其中每一个节点的左子树和右子树的高度差至多等于1。它是一种高度平衡的二叉排序树,将二叉树上结点的左子树深度减去右子树深度的值称为平衡因子BF(Balance Factor),那么平衡二叉树上所有结点的BF只能是-1,0,1。

    距离插入结点最近的,且平衡因子绝对值大于1的结点为根的子树,称为最小不平衡子树

5.2 平衡二叉树构建的基本思想

    在构建二叉排序树的过程中,每当插入一个结点时,先检查是否因插入而破坏了数的平衡性,若是,则找出最小不平衡子树。在保持二叉排序树特性的前提下,调整最小不平衡子树中各结点的链接关系,进行相应的旋转,使之成为新的不平衡子树。插入结点后,当最小不平衡子树根结点的平衡因子BF大于1时,就右旋,小于-1时就左旋;插入结点后,最小不平衡子树根结点的BF与它子树根结点的BF符号相反时,就需要对结点先进行一次旋转使得符号相同后,再反向旋转一次才能够完成平衡操作。

5.3 平衡二叉树实现算法(hard==)

/*二叉树的二叉链表结点结构定义*/
typedef struct BiTNode           //结点结构
{
	int data;                   //结点数据
	int bf;                     //结点的平衡因子
	struct BiTNode *lchild, *rchild;   //左右孩子指针
}BiTNode,*BiTree;

/*对以P为根的二叉排序树作右旋处理*/
/*处理之后的P指向新的树根结点,即旋转处理之前的左子树的根结点*/
void R_Rotate(Bitree *P)
{
	BiTree L;
	L = (*P)->lchild;              //L指向P的左子树根结点
	(*P)->lchild = L->rchild;      //L的右子树挂接为P的左子树
	L->rchild = (*P);
	*P = L;                       //P指向新的根结点
}

/*对以P为根的二叉排序树作左旋处理*/
/*处理之后的P指向新的树根结点,即旋转处理之前的右子树的根结点*/
void L_Rotate(Bitree *P)
{
	BiTree L;
	L = (*P)->rchild;              //L指向P的右子树根结点
	(*P)->rchild = L->lchild;      //L的左子树挂接为P的右子树
	L->lchild = (*P);
	*P = L;                       //P指向新的根结点
}

/*对以指针T所指结点为根的二叉树作右平衡旋转处理*/
void RightBalance(BiTree&T)
{
	BiTree R, rl;    //调用此函数时,以T为根的树,右边高于左边,则T->bf=RH。
	R = T->rchild;     //R是T的右孩子
	switch (R->bf)
	{
	case RH:            //如果 T的右孩子和T他们的平衡因子符号相同时,则直接左旋,这是总结中的第2项
		T->bf = R->bf = EH;
		L_Rotate(T);
		break;

	case EH:
		T->bf = RH;
		R->bf = LH;
		L_Rotate(T);
		break;
	case LH:         //如果T的右孩子和T他们的平衡因子符合不同时,需要先以T的右孩子为根进行右旋,再以T为根左旋。
		//rl为T的右孩子的左孩子
		rl = R->lchild;    //2次旋转后,T的右孩子的左孩子为新的根 。注意:rl的右子树挂接到R的左子树上,rl的左子树挂接到T的右子树上
		switch (rl->bf)   //这个switch 是操作T和T的右孩子进行旋转后的平衡因子。
		{
		case EH:
			T->bf = R->bf = EH;    //这些平衡因子操作,大家可以自己画图操作理解 下面的注解
			break;
			////2次旋转后,T的右孩子的左孩子为新的根 。
			//并且rl的右子树挂接到R的左子树上,rl的左子树挂接到T的右子树上,rl为新根
		case RH:
			R->bf = EH;
			T->bf = LH;
			break;

		case LH:
			R->bf = RH;
			T->bf = EH;
			break;
		default:
			break;
		}
		rl->bf = EH;
		R_Rotate(T->rchild);    //先左旋,以T->rchild为根左旋。
		L_Rotate(T);  //右旋,以T为根, 左旋后 T是和rl想等,rl是新根
		break;
	}
}

/*对以指针T所指结点为根的二叉树作左平衡旋转处理*/
void LeftBalance(BiTree&T)
{
	BiTree L, lr;
	L = T->lchild;
	switch (L->bf)
	{

	case EH:
		L->bf = RH;
		T->bf = LH;
		R_Rotate(T);
		break;
	case LH:
		L->bf = T->bf = EH;
		R_Rotate(T);
		break;
	case RH:
		lr = L->rchild;
		switch (lr->bf)
		{
		case EH:
			L->bf = L->bf = EH;
		case RH:
			T->bf = EH;
			L->bf = LH;
			break;
		case LH:
			L->bf = EH;
			T->bf = RH;
			break;
		default:
			break;
		}
		lr->bf = EH;
		L_Rotate(T->lchild);
		R_Rotate(T);
		break;
	default:
		break;
	}
}

/*主函数*/
/*若在平衡的二叉排序树T中不存在和key有相同关键字的结点,则插入一个*/
/*数据元素为key的新结点并返回1,否则返回0.若因插入而使二叉排序树*/
/*失去平衡,则作平衡旋转处理,bool变量taller反映T长高与否。*/
Status InsertAVLtree(BiTree&T, int key, bool&taller)
{
	if (!T)       //此树为空
	{
		T = new BitNode;   //直接作为整棵树的根。
		T->bf = EH;
		T->lchild = T->rchild = NULL;
		T->data = key;
		taller = true;
		return true;
	}
	else
	{
		if (key == T->data)      //已有元素,不用插入了,返回false;
		{
			taller = false;
			return false;
		}
		if (keydata)      //所插元素小于此根的值,就找他的左孩子去比
		{
			if (!InsertAVLtree(T->lchild, key, taller))   //所插元素小于此根的值,就找他的左孩子去比 
				return false;
			if (taller)    //taller为根,则树长高了,并且插入到了此根的左子树上。
			{
				switch (T->bf)       //此根的平衡因子
				{
				case EH:             //原先是左右平衡,等高
					T->bf = LH;          //由于插入到左子树上,导致左高=》》LH
					taller = true;      //继续往上递归
					break;
				case LH:
					LeftBalance(T); //原先LH,由于插入到了左边,这T这个树,不平衡需要左平衡
					taller = false;  //以平衡,设taller为false,往上递归就不用进入此语句了,
					break;
				case RH:
					T->bf = EH;     //原先RH,由于插入到左边,导致此T平衡
					taller = false;
					break;
				default:
					break;
				}
			}
		}
		else
		{
			if (!InsertAVLtree(T->rchild, key, taller))
				return false;
			if (taller)
			{
				switch (T->bf)
				{
				case EH:
					T->bf = RH;
					taller = true;
					break;
				case LH:
					T->bf = EH;
					taller = false;
					break;
				case RH:
					RightBalance(T);
					taller = false;
					break;
				default:
					break;
				}
			}
		}


	}

 

    如果我们需要查找的集合本身无顺序,在频繁查找的同时也需要经常地插入和删除操作,显然需要构建一棵二叉排序树,但是不平衡二叉排序树查找效率很低,因此需要在构建时就让这课二叉排序树是平衡二叉树。此时,查找时间复杂度为O(logn),插入和删除也为O(logn)。

 

你可能感兴趣的:(【封存】)