1. 程式人生 > >平衡二叉樹的詳解

平衡二叉樹的詳解

參考慕課課程 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;
}