1. 程式人生 > >AVL樹的平衡調整,LL,LR,RR,RL旋轉 (二)

AVL樹的平衡調整,LL,LR,RR,RL旋轉 (二)

1. 概述

AVL樹是最早提出的自平衡二叉樹,在AVL樹中任何節點的兩個子樹的高度最大差別為一,所以它也被稱為高度平衡樹。AVL樹得名於它的發明者G.M. Adelson-Velsky和E.M. Landis。AVL樹種查詢、插入和刪除在平均和最壞情況下都是O(log n),增加和刪除可能需要通過一次或多次樹旋轉來重新平衡這個樹。本文介紹了AVL樹的設計思想和基本操作。

2. 基本術語

有四種種情況可能導致二叉查詢樹不平衡,分別為:

(1)LL:插入一個新節點到根節點的左子樹(Left)的左子樹(Left),導致根節點的平衡因子由1變為2

(2)RR:插入一個新節點到根節點的右子樹(Right)的右子樹(Right),導致根節點的平衡因子由-1變為-2

(3)LR:插入一個新節點到根節點的左子樹(Left)的右子樹(Right),導致根節點的平衡因子由1變為2

(4)RL:插入一個新節點到根節點的右子樹(Right)的左子樹(Left),導致根節點的平衡因子由-1變為-2

針對四種種情況可能導致的不平衡,可以通過旋轉使之變平衡。有兩種基本的旋轉:

(1)左旋轉:將根節點旋轉到(根節點的)右孩子的左孩子位置

(2)右旋轉:將根節點旋轉到(根節點的)左孩子的右孩子位置

3. AVL樹的旋轉操作

AVL樹的基本操作是旋轉,有四種旋轉方式,分別為:左旋轉,右旋轉,左右旋轉(先左後右),右左旋轉(先右後左),實際上,這四種旋轉操作兩兩對稱,因而也可以說成兩類旋轉操作。

基本的資料結構:

1 2 3 4 5 6 7 8 9 10 11 12 13 typedefstruct Node* Tree; typedefstruct Node* Node_t; typedefType int; structNode{ Node_t left; Node_t right; intheight; Type data; }; int Height(Node_t node) { returnnode->height; }

3.1 LL

LL情況需要右旋解決,如下圖所示:

程式碼為:

1 2 3 4 5 6 7 8 Node_t RightRotate(Node_t a) {
b = a->left; a->left = b->right; b->right = a; a->height = Max(Height(a->left), Height(a->right)); b->height = Max(Height(b->left), Height(b->right)); returnb; }

3.2 RR

RR情況需要左旋解決,如下圖所示:

程式碼為:

1 2 3 4 5 6 7 8 Node_t LeftRotate(Node_t a) { b = a->right; a->right = b->left; b->left = a; a->height = Max(Height(a->left), Height(a->right)); b->height = Max(Height(b->left), Height(b->right)); returnb; }

3.3 LR

LR情況需要左右(先B左旋轉,後A右旋轉)旋解決,如下圖所示:

程式碼為:

1 2 3 4 Node_t LeftRightRotate(Node_t a) { a->left = LeftRotate(a->left); returnRightRotate(a); }

3.4 RL

RL情況需要右左旋解決(先B右旋轉,後A左旋轉),如下圖所示:

程式碼為:

1 2 3 4 Node_t RightLeftRotate(Node_t a) { a->right = RightRotate(a->right); returnLeftRotate(a); }

#include<stdio.h>
#include <stdlib.h>

typedef struct _Tree
{
 int nValue;
 struct _Tree* pLeft;
 struct _Tree* pRight;
 struct _Tree* pFather;
}Tree;

Tree* root = NULL;


void CreateTree()
{

 root = (Tree*)malloc(sizeof(Tree));
 root->nValue = 1;
 root->pFather = NULL;

 root->pLeft = (Tree*)malloc(sizeof(Tree));
 root->pLeft->nValue = 2;
 root->pLeft->pFather = root;

 root->pLeft->pLeft = (Tree*)malloc(sizeof(Tree));
 root->pLeft->pLeft->nValue = 4;
 root->pLeft->pLeft->pLeft = NULL;
 root->pLeft->pLeft->pRight = NULL;
 root->pLeft->pLeft->pFather = root->pLeft;

 root->pLeft->pRight = (Tree*)malloc(sizeof(Tree));
 root->pLeft->pRight->nValue = 5;
 root->pLeft->pRight->pLeft = NULL;
 root->pLeft->pRight->pRight = NULL;
 root->pLeft->pRight->pFather = root->pLeft;

 root->pRight = (Tree*)malloc(sizeof(Tree));
 root->pRight->nValue = 3;
 root->pRight->pLeft = NULL;
 root->pRight->pRight = NULL;
 root->pRight->pFather = root;
}

void Rotate_Right(Tree* tree)
{
 Tree* temp = tree->pLeft;
 // 修改三個子節點
 tree->pLeft = temp->pRight;
 temp->pRight = tree;
 if (tree->pFather == NULL)
 {
  root = temp;
 }
 else
 {
  //  看  tree   原來  放在他父親節點的  左邊還是右邊
  if (tree->pFather->pLeft == tree)
  {
   tree->pFather->pLeft = temp;
  }
  else
  {
   tree->pFather->pRight = temp;
  }
 }
 // 修改 三個父親
 temp->pFather = tree->pFather;
 tree->pFather = temp;
 //   看 tree  有沒有左
 if(tree->pLeft != NULL)
 {
  tree->pLeft->pFather = tree;
 }
}


void Rotate_Left(Tree* tree)
{

 Tree* temp = tree->pRight;
 // 修改三個子節點
 tree->pRight = temp->pLeft;
 temp->pLeft = tree;
 if (tree->pFather == NULL)
 {
  root = temp;
 }
 else
 {
  //  看  tree   原來  放在他父親節點的  左邊還是右邊
  if (tree->pFather->pLeft == tree)
  {
   tree->pFather->pLeft = temp;
  }
  else
  {
   tree->pFather->pRight = temp;
  }
 }
 // 修改 三個父親
 temp->pFather = tree->pFather;
 tree->pFather = temp;
 //   看 tree  有沒有左
 if(tree->pRight != NULL)
 {
  tree->pRight->pFather = tree;
 }
}


void Qian(Tree* tree)
{
 if (tree)
 {
  printf("%d ",tree->nValue);
  Qian(tree->pLeft);
  Qian(tree->pRight);
 }
}


int main()
{

 CreateTree();
 Qian(root);
 printf("\n-----------------------\n");

 Rotate_Right(root);
 Qian(root);
 printf("\n-----------------------\n");

 Rotate_Left(root);
 Qian(root);
 printf("\n-----------------------\n");

 system("pause");
 return 0;
}