平衡二叉樹的詳解
阿新 • • 發佈:2018-11-22
參考慕課課程 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;
}