平衡二叉树的详解

参考慕课课程 https://www.icourse163.org/learn/ZJU-93001?tid=1003013004#/learn/content?type=detail&id=1004242207&cid=1005239477
参考数据结构与算法分析----C语言描述
如有错误,请指出
树的结构

typedef struct AVLNode *Position;
typedef Position AVLTree; /* AVL树类型 */
struct AVLNode {
	int Data; /* 结点数据 */
	AVLTree Left;     /* 指向左子树 */
	AVLTree Right;    /* 指向右子树 */
	int Height;       /* 树高 */
};

建立一颗空树

AVLTree createTree(AVLTree T)
{
	if (T)
	{
		createTree(T->Left);
		createTree(T->Right);
		free(T);
	}
	return NULL;
}

得到树节点的高度

int GetHeight(Position T)
{
	if (T == NULL)
	{
		return -1;
	}
	else 
		return T->Height;

找到最大节点

AVLTree FindMax(AVLTree T)
{
	if (T)
		while (T->Right)
			T = T->Right;
	return T;
}

判断两个数大小

int Max(int a,int b)
{
	return a > b ? a : b;
}

平衡二叉树的四种调整方式
右单旋
在这里插入图片描述

AVLTree SingleRotateWithRight(Position K) //右单旋
{
	Position K1;
	K1 = K->Right;
	K->Right = K1->Left;
	K1->Left = K;

	K->Height = Max(GetHeight(K->Left), GetHeight(K->Right))+1; //重新调整树的高度
	K1->Height = Max(GetHeight(K1->Left), GetHeight(K1->Right))+1; // 重新调整树的高度
	return K1;
}

左单旋
在这里插入图片描述

AVLTree SingleRotateWithLeft(Position K) //左单旋
{
	Position K1;
	K1 = K->Left;
	K->Left = K1->Right;
	K1->Right = K;

	K->Height = Max(GetHeight(K->Left), GetHeight(K->Right))+1; //重新调整树的高度
	K1->Height = Max(GetHeight(K1->Left), GetHeight(K1->Right))+1;  //重新调整树的高度
	return K1;
}

左右双旋
在这里插入图片描述

AVLTree DoubleRotateWithLeft(Position K) // 左右双旋
{
	K->Left = SingleRotateWithRight(K->Left); //先右旋
	return SingleRotateWithLeft(K); // 后左旋
}

右左双旋
在这里插入图片描述

AVLTree DoubleRotateWithRight(Position K) // 右左双旋
{
	K->Right = SingleRotateWithLeft(K->Right);  //先左旋
	return SingleRotateWithRight(K); // 后右旋
}

看图片理解代码
看不懂可以在机器上运行,看运行的过程
插入操作

AVLTree InsertTree(AVLTree T,int X)
{
	if (T == NULL)
	{
		T = (AVLTree)malloc(sizeof(struct AVLNode));
		T->Data = X;
		T->Height = 0;
		T->Left = T->Right = NULL;
	}
	else if (T->Data < X) // 向右插入
	{
		T->Right = InsertTree(T->Right, X); 
		if (GetHeight(T->Right) - GetHeight(T->Left) == 2) //在插入后检测树的平衡性
		{
			if (T->Right->Data < X)  // 插入节点在右子树上,做单右旋转
			{
				T = SingleRotateWithRight(T);
			}
			else   // 插入节点在左子树做右左双旋
			{
				T = DoubleRotateWithRight(T);
			}
		}
	}
	else if (T->Data > X) //向左插入
	{
		T->Left = InsertTree(T->Left, X);
		if (GetHeight(T->Left) - GetHeight(T->Right) == 2) //在插入后检测树的平衡性
		{
			if (T->Left->Data > X) //插入节点在左子树,做单左旋转
			{
				T = SingleRotateWithLeft(T);
			}
			else  // 插入节点在右子树 ,做左右双旋
			{
				T = DoubleRotateWithLeft(T);
			}
		}
	}
	T->Height = Max(GetHeight(T->Left), GetHeight(T->Right))+1; // 插入完成后,更新树的高度
	return T;
}

删除操作
与二叉树的删除一致,只是删除之后要检测二叉树是不是平衡,更新二叉树各个节点的高度

AVLTree DeleteTree(AVLTree T, int X)
{
	AVLTree Tmp;
	if (T == NULL)
	{
		return NULL;
	}
	if (X < T->Data) // 向左查找删除
	{
		T->Left = DeleteTree(T->Left, X);
		T->Height = Max(GetHeight(T->Left), GetHeight(T->Right)) + 1; // 删除之后更新节点的高度
		if (GetHeight(T->Right) - GetHeight(T->Left) == 2) //判断是否平衡
		 {
			AVLTree tmp = T->Right; //此处应该判断T->Right不为空
			if (GetHeight(tmp->Left) > GetHeight(tmp->Right)) // 左子树节点高,做右左双旋
				T = DoubleRotateWithRight(T);
			else  // 右子树高,做单右旋转
				T = SingleRotateWithRight(T);
		}
	}
	else if (X > T->Data) //向右查找删除
	{
		T->Right = DeleteTree(T->Right, X);
		T->Height = Max(GetHeight(T->Left), GetHeight(T->Right)) + 1; //更新树的高度
		if (GetHeight(T->Left) - GetHeight(T->Right) == 2) // 判断树是否平衡
		 {
			AVLTree tmp = T->Left; // 此处应该判断 T->Left 不为空
			if (GetHeight(tmp->Right) > GetHeight(tmp->Left))  //右子树高,做左右双旋
			{
				T = DoubleRotateWithLeft(T);
			}
			else  // 左子树高,做单左旋转
			{
				T = SingleRotateWithLeft(T);
			}
		}
	}
	else
	{
		if (T->Left && T->Right)
		{
			Tmp = FindMax(T->Left); // 找出左子树最大节点,代替被删除节点
			T->Data = Tmp->Data;
			T->Left = DeleteTree(T->Left, T->Data);
		}
		else
		{
			Tmp = T;
			if (T->Left == NULL)
			{
				T = T->Right;
			}
			else if (T->Right == NULL)
			{
				T = T->Left;
			}
			free(Tmp);
		}
	}
	return T;
}

猜你喜欢

转载自blog.csdn.net/weixin_40540957/article/details/83794815