二叉搜索樹之AVL樹



AVL樹在ROS系統中應用廣泛,如路由表管理模塊和FEC表,這些大容量又操作頻繁的數據,採用AVL樹存儲結構可以有效提高系統效率。

AVL樹又稱爲高度平衡的二叉搜索樹(BST),是1962年由兩位俄羅斯數學家GMAdel’ son-Vel'skyEMLandis在論文《An algorithm for theorganization of information》中提出的。引入它的目的,是爲了提高BST的搜索效率,即減少平均搜索長度。爲此,向BST中每插入或刪除一個新結點時,就必須調整樹的結構,使得BST繼續保持平衡,從而儘可能降低樹的高度。

 

下面先講講AVL樹的一些基本概念:

AVL樹的定義:一棵ALV樹或者是空樹,或者是具有下列性質的二叉搜索樹:它的左子樹和右子樹都是AVL樹,且左子樹和右子樹的高度之差的絕對值不超過1

AVL樹的高度:(固定節點數計算最大高度)

N(h)爲一棵高度爲hAVL樹具有的最小節點數,則最壞情況是它的左右子樹的高度不等,即一個是N(h-1)和另一個是N(h-2),從而得到,

N(h)=N(h-1)+N(h-2)+1,N(0)=0, N(1)=1

上述類似於Fibonacci數列:F(n)=F(n-1)+F(n-2), F(0)=0, F(1)=1

F(h)=(1+sqrt(5))^h/sqrt(5),N(h) = F(h+3)-1,h>=0,

h = 1.44log2(N(h)+1)-1.33

從而高度h和節點數是對數關係,因此h=O(log(N(h)))

由此容易知道在不考慮恢復AVL樹的前提下,它的插入、刪除和查找的工作量不超過O(n)


樹的一些概念

圖(父結點,祖父結點,兄弟結點,叔叔結點、左孩子、右孩子)


旋轉(不改變BST性質)

左旋:

右旋:

細分4種類型:

LL型

LR型

RR型

RL型

平衡因子的調整

 

如果一棵二叉搜索樹是高度平衡的,它就成爲AVL樹,如果它有N個結點,其高度可保持在O(log2n),平均搜索長度也可保持在O(log2n)。


樹的旋轉:

在介紹插入和刪除操作之前首先介紹樹的旋轉操作

樹的旋轉操作是爲了改變樹的結構,使其達到平衡。旋轉總共分爲左旋和右旋兩類

左旋

如圖爲樹的以B爲軸左旋示意圖(反過來看,從右到左是以A爲軸右旋)。樹的旋轉操作要特別注意兒子節點是否爲空

頂層節點是否爲根節點。


AVL樹的插入操作:

插入操作只會改變被插入節點到根節點路徑上的節點的平衡因子。

因爲在插入之前樹是AVL樹,因此各個節點的平衡因子是1-10

一、如果路徑上節點平衡因子是0,則插入後不會打破這個節點的平衡性。

二、如果路徑上的節點的平衡因子是1-1,則可能會打破平衡性,在這種情況下如果此節點的新的平衡

因子是0,則剛好將其補的更加平衡,平衡性未打破;否則平衡因子變成2-2,則需要進行調整。

三、我們在對樹進行調整後恢復子樹相對於插入前的高度,不改變子子樹的平衡因子。

由以上三點:只需向根部查找從插入點開始第一個平衡因子不爲0的節點,令該節點爲A

更新步驟:

(1).若A不存在,說明插入節點不影響平衡性,則自下而上更新平衡因子直到根部即可。

(2).bf(A)=1且插入節點在A地右子樹中,或者bf(A)=-1且插入節點在A的左子樹中,則自下而上更新

平衡因子直到A。(注:A的平衡因子變爲0

(3).A的平衡性被打破,首先依然自下而上更新平衡因子,在按照下面進行分類:LL, LR, RR, RL

bf(A)=1,新的bf(A)=2, LL, LR,

bf(A)=-1,新的bf(A)=-2, RR, RL

如圖爲RR的情況,LL情況類似,旋轉後只需再次改變兩個節點的平衡因子

RR

如下圖爲RL的情況,LR類似,旋轉後需要再次改變三個節點的平衡因子

RL

至此,插入操作已經完成,可見最多多做兩次旋轉操作調整樹的結構使之平衡。


AVL樹的刪除操作:

刪除操作和插入操作一樣,也是先直接刪除二叉樹節點,然後在更新平衡因子,

調整AVL樹使之平衡。

這裏所指的刪除的節點是實際被刪除的節點,刪除操作不影響其子樹的平衡因子。

首先刪除節點,然後沿着該節點的父節點向根部更新平衡因子,考慮更新後的節點A

新的平衡因子,分爲下面三種情況:

(1)、如果bf(A)=0,則高度減少了1,從而繼續向上找非平衡點。

(2)、如果bf(A)=1或者-1,則之前必爲0,從而不影響平衡性,結束。

(3)、如果bf(A)=2(原來爲1)或者-2(原來爲-1),則A點非平衡。調整。

bf(A)=-2爲例,稱AL不平衡

如果A的右節點的平衡因子是0,則進行一次左旋轉,如圖:

L0

由於子樹的高度和刪除前一樣,因此樹已經平衡。

如果A的右節點的平衡因子是-1,則稱爲L-1不平衡,也要進行一次做旋轉。

L-1

樹的高度減少1,這使得上面的祖先節點可能不平衡,一次還要沿着路徑在向上

尋找新的不平衡點,再次更新平衡因子,調整等。

如果A的右節點的平衡因子是1,則稱爲L1不平衡,要進行兩次旋轉。

L1

此時要根據BL的情況決定AB的新的平衡因子。

由於樹的高度減少了1,因此還要沿着路徑繼續向上尋找新的不平衡點。

至此樹節點的刪除操作完成。


總結:

歸納起來,AVL樹的查找操作(符合中序遍歷)等同於一般二叉搜索樹,插入和刪除操作除了一般的二叉樹插入和刪除,還要更新樹的平衡因子,當平衡因子被打破時要通過旋轉恢復。而且在調整平衡時儘量影響局部範圍。平衡調整過程總是至下而上進行,把不平衡消滅在最開始階段。


最後附上avl實現源碼,在VC6.0上驗證通過。

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/*****************************************************************
 * 文件名:AVL.c
 * 需求:  實現AVL樹的插入、刪除、查找、遍歷等基本功能
 * 作者:  韓立忠  2012.04.10
 ****************************************************************/

/************************* 引入的頭文件 *************************/

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

/**************************** 宏定義 ****************************/

#define DEBUG_VERSION 1

#if DEBUG_VERSION
#define ASSERT(x) assert(x)
#else
#define ASSERT(x) (1 == 1)
#endif

/* 宏定義棧深度 */
#define STACK_SIZE 40

/************************* 定義數據結構 *************************/

/* 函數返回值的枚舉 */
enum
{
 FALSE = 0,
 TRUE  = 1,
 ERROR = 0xffffffff
};

/* typedefs */
typedef int status_t;
typedef int BOOL;
typedef int key_t;  /* 可根據用戶需要定義爲多成員變量的結構體 */
typedef int data_t;

/* 定義AVL樹結點平衡因子的枚舉類型 */
typedef enum BF_E
{
 EH = 0,    /* 等高 */
 LH = 1,    /* 左高 */
 RH = 2     /* 右高 */
}bf_e;

/* 定義AVL樹結點相對於父結點位置關係的枚舉類型 */
typedef enum POS_E
{
 ROOT = 0,        /* 標識本結點爲根結點 */
 LCHILD = 1,      /* 標識本結點爲父結點的左孩子 */
 RCHILD = 2       /* 標識本結點爲父結點的右孩子 */
}pos_e;

/* 定義AVL樹的數據結點 */
typedef struct avlNode_s
{
 //struct avlNode_s *prev;  /* 用於AVL樹的線索化 */
 //struct avlNode_s *next;
 struct avlNode_s *lChild;  /* 指向左孩子的指針 */
 struct avlNode_s *rChild;  /* 指向右孩子的指針 */
 bf_e bf;                   /* 結點的平衡因子 */
}avlNode_t;

/* 用戶定義的AVL樹數據結點 */
typedef struct myAvlNode_s
{
 //struct myAvlNode_s *prev;  /* 用於AVL樹的線索化 */
 //struct myAvlNode_s *next;
 struct myAvlNode_s *lChild;  /* 指向左孩子的指針 */
 struct myAvlNode_s *rChild;  /* 指向右孩子的指針 */
 bf_e bf;                      /* 結點的平衡因子 */
 key_t key;                    /* 鍵值項 */
 //data_t data;                  /* 數據項 */
}myAvlNode_t;

/* 定義緩存棧,用於存放AVL樹搜索路徑上的結點指針 */
typedef struct stack_s
{
 avlNode_t *buff[STACK_SIZE];  /* 記錄結點指針 */
 pos_e pos[STACK_SIZE];        /* 記錄結點相對於父結點的位置關係 */
 unsigned char top;            /* 棧頂指針 */
 char res[3];                  /* 保留bit,用於字節對齊 */
}stack_t;

/************************* 定義回調函數 *************************/

typedef int (*nodeCmp_f)(avlNode_t *, avlNode_t *);
typedef void (*nodeCpy_f)(avlNode_t *, avlNode_t *);
typedef void (*nodeFree_f)(avlNode_t *);
typedef void (*nodePrint_f)(avlNode_t *);

/* 定義AVL樹指向根結點的Root結點 */
typedef struct avlRoot_s
{
 avlNode_t *root;           /* 指向AVL根結點的指針 */
 unsigned int count;        /* AVL結點總數 */
 unsigned char height;      /* AVL樹高度 */
 char res[3];
 nodeCmp_f nodeCmp;        /* 結點鍵值比較函數 */
 nodeCpy_f nodeCpy;        /* 結點數據複製函數 */
 nodeFree_f nodeFree;       /* 結點內存釋放函數 */
 nodePrint_f nodePrint;     /* 結點數據打印函數 */
}avlRoot_t;

/************************* 全局函數聲明 *************************/

/* AVL樹結點插入操作 */
status_t AVL_insert(avlRoot_t *pRoot, avlNode_t *pNode);
/* AVL樹結點刪除操作 */
status_t AVL_delete(avlRoot_t *pRoot, avlNode_t *pNode);
/* AVL樹查找函數 */
avlNode_t *AVL_find(avlRoot_t *pRoot, avlNode_t *pfindNode);
/* AVL樹查找函數(遞歸方法) */
avlNode_t *AVL_find_R(avlNode_t *pNode, avlNode_t *pfindNode);
/* 根據當前data值查找其父結點函數 */
avlNode_t *AVL_findParent(avlRoot_t *pRoot, avlNode_t *pNode);
/* AVL樹中序遍歷函數 */
void AVL_traverseInOrder(avlRoot_t *pRoot);
/* AVL樹結點內存釋放函數 */
void AVL_free(avlRoot_t **ppRoot);

/*-------------------------- 內部函數 --------------------------*/

static void leftRotate(avlNode_t **P);     /* AVL樹以根結點P左旋處理函數 */
static void rightRotate(avlNode_t **P);    /* AVL樹以根結點P右旋處理函數 */
static void leftBalance(avlNode_t **T);    /* AVL樹以T爲根結點作左平衡處理函數 */
static void rightBalance(avlNode_t **T);   /* AVL樹以T爲根結點作右平衡處理函數 */

/*------------------------ 用戶定義函數 ------------------------*/

void AVL_rootInit(avlRoot_t **ppRoot);             /* AVL樹根節點初始化函數 */
avlNode_t *encapNode(key_t *key);
int nodeCmp(avlNode_t *pNode1, avlNode_t *pNode2); /* AVL樹結點鍵值比較函數 */
void nodeFree(avlNode_t *pNode);                   /* AVL樹結點內存釋放函數 */
void nodePrint(avlNode_t *pNode);                  /* AVL樹結點數據打印函數 */

/*------------------------ 棧的相關函數 ------------------------*/

static void stackInit(stack_t **);                             /* 棧初始化函數 */
static void stackPush(stack_t *, avlNode_t *, pos_e);          /* 壓棧函數 */
static void stackPop(stack_t *, avlNode_t **, pos_e *);        /* 出棧函數 */
static void stackGet(stack_t *, avlNode_t **, pos_e *);        /* 取棧頂元素函數 */
static void stackReplace(stack_t *, avlNode_t *, avlNode_t *); /* 棧元素替換函數 */
static void stackFree(stack_t **);                             /* 棧內存釋放函數 */
static BOOL stackIsEmpty(stack_t *);                           /* 判棧是否爲空函數 */

/************************* 定義全局變量 *************************/

#define N 10000
//key_t a[10] = {3, 2, 1, 4, 5, 6, 7, 10, 9, 8};
key_t a[N] = {0};

/****************************************************************/

/**************************** 主函數 ****************************/

void test(void)
{
 int i = 0;
 avlRoot_t *pRoot = NULL;
 avlNode_t *pNode = NULL;

 AVL_rootInit(&pRoot);
 for (i = 0; i < N; i++)
 {
  a[i] = i + 1;
 }

 for (i = 0; i < N; i++)
 {
  AVL_insert(pRoot, encapNode(&a[i]));
 }
 AVL_traverseInOrder(pRoot);

 for (i = N/20; i < N*3/4; i++)
 {
  pNode = encapNode(&a[i]);
  AVL_delete(pRoot, pNode);
  pRoot->nodeFree(pNode);
 }
 AVL_traverseInOrder(pRoot);

 AVL_free(&pRoot);

 return;
}

void main(void)
{
 test();
 return;
}

/****************************************************************/
/****************************************************************/

/* AVL樹以根結點P右旋處理函數 */
static void rightRotate(avlNode_t **P)
{
 avlNode_t *L = NULL;
 if ((NULL == P) || (NULL == *P))
 {
  ASSERT(0);
  return;
 }

 L = (*P)->lChild;
 ASSERT(L != NULL);
 (*P)->lChild = L->rChild;
 L->rChild = *P;
 *P = L;     /* P指向新的根結點 */

 return;
}

/* AVL樹以根結點P左旋處理函數 */
static void leftRotate(avlNode_t **P)
{
 avlNode_t *R = NULL;
 if ((NULL == P) || (NULL == *P))
 {
  ASSERT(0);
  return;
 }

 R = (*P)->rChild;
 ASSERT(R != NULL);
 (*P)->rChild = R->lChild;
 R->lChild = *P;
 *P = R;

 return;
}

/* AVL樹以T所指結點爲根作左平衡旋轉處理函數,算法結束T指向新的根節點 */
static void leftBalance(avlNode_t **T)
{
 avlNode_t *L = NULL;
 avlNode_t *Lr = NULL;
 if ((NULL == T) || (NULL == *T))
 {
  ASSERT(0);
  return;
 }

 L = (*T)->lChild;
 ASSERT(L != NULL);
 /* 檢查T左子樹的平衡度,並作相應平衡處理 */
 switch (L->bf)
 {
 case LH:  /* T左孩子左高,作LL單旋處理 */
  {
   (*T)->bf = EH;
   L->bf = EH;
   rightRotate(T);
   break;
  }
 case RH:  /* T左孩子右高,作LR雙旋處理 */
  {
   Lr = L->rChild;
   ASSERT(Lr != NULL);
   /* 根據T左孩子的右孩子bf,修改T及其左孩子的bf */
   switch (Lr->bf)
   {
   case LH:
    {
     (*T)->bf = RH;
     L->bf = EH;
     break;
    }
   case EH:
    {
     (*T)->bf = EH;
     L->bf = EH;
     break;
    }
   case RH:
    {
     (*T)->bf = EH;
     L->bf = LH;
     break;
    }
   default:
    {
     ASSERT(0);
     return;
    }
   }
   Lr->bf = EH;
   leftRotate(&((*T)->lChild)); /* 對T的左子樹作左旋處理 */
   rightRotate(T);              /* 對T作右旋處理 */
   break;
  }
 case EH:  /* T左右孩子等高,僅刪除操作時會出現該情況 */
  {
   (*T)->bf = LH;
   L->bf = RH;
   rightRotate(T);
   break;
  }
 default:
  {
   ASSERT(0);
   return;
  }
 }

 return;
}

/* AVL樹以T所指結點爲根作右平衡旋轉處理函數,算法結束T指向新的根節點 */
static void rightBalance(avlNode_t **T)
{
 avlNode_t *R = NULL;
 avlNode_t *Rl = NULL;
 if ((NULL == T) || (NULL == *T))
 {
  ASSERT(0);
  return;
 }

 R = (*T)->rChild;
 ASSERT(R != NULL);
 /* 檢查T右子樹的平衡度,作相應平衡處理 */
 switch (R->bf)
 {
 case LH:  /* T右孩子左高,作RL雙旋處理 */
  {
   Rl = R->lChild;
   ASSERT(Rl != NULL);
   switch (Rl->bf)
   {
   case LH:
    {
     (*T)->bf = EH;
     R->bf = RH;
     break;
    }
   case EH:
    {
     (*T)->bf = EH;
     R->bf = EH;
     break;
    }
   case RH:
    {
     (*T)->bf = LH;
     R->bf = EH;
     break;
    }
   default:
    {
     ASSERT(0);
     return;
    }
   }
   Rl->bf = EH;
   rightRotate(&((*T)->rChild)); /* 對T的右子樹作右旋處理 */
   leftRotate(T);                /* 對T作左旋處理 */
   break;
  }
 case RH:  /* T右孩子右高,作RR單旋處理 */
  {
   (*T)->bf = EH;
   R->bf = EH;
   leftRotate(T);
   break;
  }
 case EH:  /* T左右孩子等高,僅刪除操作會出現該情況 */
  {
   (*T)->bf = RH;
   R->bf = LH;
   leftRotate(T);
   break;
  }
 default:
  {
   ASSERT(0);
   return;
  }
 }

 return;
}

/* AVL樹根節點初始化函數 */
void AVL_rootInit(avlRoot_t **ppRoot)
{
 if (NULL == ppRoot)
 {
  ASSERT(0);
  return;
 }

 *ppRoot = (avlRoot_t *)malloc(sizeof(avlRoot_t));
 if (NULL == *ppRoot)
 {
  ASSERT(0);
  return;
 }

 memset(*ppRoot, 0, sizeof(avlRoot_t)); 
 (*ppRoot)->nodeCmp = nodeCmp;
 (*ppRoot)->nodeFree = nodeFree;
 (*ppRoot)->nodePrint = nodePrint;
 
 return;
}

/* AVL樹插入函數 */
status_t AVL_insert(avlRoot_t *pRoot, avlNode_t *pNode)
{
 stack_t *pStack = NULL;
 pos_e pos = ROOT;
 pos_e parPos = ROOT;
 pos_e childPos = ROOT;
 avlNode_t *pTmpNode = NULL;
 avlNode_t *pParNode = NULL;
 int rtnValue = 0;
 
 if ((NULL == pRoot) || (NULL == pNode))
 {
  ASSERT(0);
  return ERROR;
 }

 /* 樹爲空,直接插入新結點返回 */
 pTmpNode = pRoot->root;
 if (NULL == pTmpNode)
 {
  pRoot->root = pNode;
  pRoot->count = 1;
  pRoot->height = 1;
  return TRUE;
 }

 /* 該棧用於記錄搜索路徑上的結點指針和相對於上級結點的位
 置關係,記錄結點包括根結點和最後的NULL指針 */
 stackInit(&pStack);
 stackPush(pStack, pTmpNode, ROOT);  /* 記錄根結點 */

 /* (1)樹不爲空,查找插入位置 */
 do
 {
  rtnValue = pRoot->nodeCmp(pNode, pTmpNode);
  /* 樹中已存在相同結點,不再插入 */
  if (0 == rtnValue)
  {
   pRoot->nodeFree(pNode);
   stackFree(&pStack);
   return FALSE;
  }

  if (rtnValue < 0)
  {
   pTmpNode = pTmpNode->lChild;
   stackPush(pStack, pTmpNode, LCHILD);
  }
  else
  {
   pTmpNode = pTmpNode->rChild;
   stackPush(pStack, pTmpNode, RCHILD);
  }
 } while (pTmpNode != NULL);

 /* (2)找到插入位置,執行插入操作 */
 stackPop(pStack, &pTmpNode, &pos);
 ASSERT((NULL == pTmpNode) && (LCHILD == pos) || (RCHILD == pos));
 ASSERT(!stackIsEmpty(pStack));
 stackGet(pStack, &pParNode, &parPos);
 ASSERT(pParNode != NULL);
 if (LCHILD == pos)
 {
  pParNode->lChild = pNode;
 }
 else
 {
  pParNode->rChild = pNode;
 }
 pRoot->count++;

 /* (3)已插入結點,執行平衡處理 */
 do
 {
  childPos = pos;
  stackPop(pStack, &pTmpNode, &pos);
  /* 若插入在pTmpNode結點左子樹上 */
  if (LCHILD == childPos)
  {
   /* 檢查pTmpNode的平衡度 */
   switch (pTmpNode->bf)
   {
   case LH:  /* 原本左子樹比右子樹高,作左平衡處理 */
    {
     leftBalance(&pTmpNode);
     /* 平衡處理後,重新連好pTmpNode與父結點的關係 */
     if (stackIsEmpty(pStack))
     {
      ASSERT(ROOT == pos);
      pRoot->root = pTmpNode;
     }
     else
     {
      ASSERT((LCHILD == pos) || (RCHILD == pos));
      stackGet(pStack, &pParNode, &parPos);
      ASSERT(pParNode != NULL);
      if (LCHILD == pos)
      {
       pParNode->lChild = pTmpNode;
      }
      else
      {
       pParNode->rChild = pTmpNode;
      }
     }
     stackFree(&pStack);
     return TRUE;
    }
   case EH:  /* 原本左右子樹等高,現因左子樹增高而增高 */
    {
     pTmpNode->bf = LH;
     if (pTmpNode == pRoot->root)
     {
      pRoot->height++;
     }
     break;
    }
   case RH:  /* 原本右子樹比左子樹高,現左右子樹等高 */
    {
     pTmpNode->bf = EH;
     stackFree(&pStack);
     return TRUE;
    }
   default:
    {
     ASSERT(0);
     stackFree(&pStack);
     return ERROR;
    }
   }
  }
  /* 若插入在pTmpNode結點右子樹上 */
  else
  {
   ASSERT(RCHILD == childPos);
   switch (pTmpNode->bf)
   {
   case LH:  /* 原本左子樹比右高,現左右等高 */
    {
     pTmpNode->bf = EH;
     stackFree(&pStack);
     return TRUE;
    }
   case EH:  /* 原本左右子樹等高,現因右增高而增高 */
    {
     pTmpNode->bf = RH;
     if (pTmpNode == pRoot->root)
     {
      pRoot->height++;
     }
     break;
    }
   case RH:  /* 原本右子樹比左高,作右平衡處理 */
    {
     rightBalance(&pTmpNode);
     if (stackIsEmpty(pStack))
     {
      ASSERT(ROOT == pos);
      pRoot->root = pTmpNode;
     }
     else
     {
      ASSERT((LCHILD == pos) || (RCHILD == pos));
      stackGet(pStack, &pParNode, &parPos);
      ASSERT(pParNode != NULL);
      if (LCHILD == pos)
      {
       pParNode->lChild = pTmpNode;
      }
      else
      {
       pParNode->rChild = pTmpNode;
      }
     }
     stackFree(&pStack);
     return TRUE;
    }
   default:
    {
     ASSERT(0);
     stackFree(&pStack);
     return ERROR;
    }
   }
  }
 } while (!stackIsEmpty(pStack));
 
 stackFree(&pStack);
 return TRUE;
}

/* AVL樹刪除函數 */
status_t AVL_delete(avlRoot_t *pRoot, avlNode_t *pNode)
{
 stack_t *pStack = NULL;
 BOOL lower = FALSE;
 pos_e pos = ROOT;         /* 該結點相應於上級結點的位置關係 */
 pos_e dPos = ROOT;
 pos_e nPos = ROOT;
 pos_e parPos = ROOT;
 pos_e dParPos = ROOT;
 pos_e nParPos = ROOT;
 pos_e childPos = ROOT;
 avlNode_t *pTmpNode = NULL;
 avlNode_t *pParNode = NULL;     /* 父結點 */
 avlNode_t *pDelNode = NULL;     /* 待刪結點 */
 avlNode_t *pDelParNode = NULL;  /* 待刪結點的父結點 */
 avlNode_t *pNearNode = NULL;    /* 待刪結點的直接前驅或後繼結點 */
 avlNode_t *pNearParNode = NULL; /* 鄰近結點的父結點 */
 int rtnValue = 0;
 
 if ((NULL == pRoot) || (NULL == pNode))
 {
  ASSERT(0);
  return ERROR;
 }

 pTmpNode = pRoot->root;
 /* 該棧用於記錄搜索路徑的結點指針和相對上級結點的位置,
 包括根結點,或包括最後的NULL指針 */
 stackInit(&pStack);
 stackPush(pStack, pTmpNode, ROOT);   /* 記錄根結點 */

 /* (1)查找刪除結點位置 */
 while (pTmpNode != NULL)
 {
  rtnValue = pRoot->nodeCmp(pNode, pTmpNode);
  /* 找到待刪結點,跳出循環 */
  if (0 == rtnValue)
  {
   break;
  }

  if (rtnValue < 0)
  {
   pTmpNode = pTmpNode->lChild;
   stackPush(pStack, pTmpNode, LCHILD);
  }
  else
  {
   pTmpNode = pTmpNode->rChild;
   stackPush(pStack, pTmpNode, RCHILD);
  }
 }

 /* 未找到待刪結點,返回FALSE */
 if (NULL == pTmpNode)
 {
  stackFree(&pStack);
  return FALSE;
 }

 /* (2)找到待刪結點,執行刪除操作 */
 stackPop(pStack, &pDelNode, &dPos);  /* 彈出待刪結點 */
 if (stackIsEmpty(pStack))
 {
  ASSERT((pDelNode == pRoot->root) && (ROOT == dPos));
 }
 else
 {
  ASSERT((LCHILD == dPos) || (RCHILD == dPos));
  stackGet(pStack, &pDelParNode, &dParPos);
  ASSERT(pDelParNode != NULL);
 }
 
 /* (2)-1若待刪結點右孩子爲空,或左右孩子都空 */
 if (NULL == pDelNode->rChild)
 {
  if (pDelNode == pRoot->root)
  {
   pRoot->root = pDelNode->lChild;
  }
  else
  {
   if (LCHILD== dPos)
   {
    pDelParNode->lChild = pDelNode->lChild;
   }
   else
   {
    pDelParNode->rChild = pDelNode->lChild;
   }
  }

  /* 記錄待刪結點位置,用於後續平衡處理 */
  stackPush(pStack, (avlNode_t *)NULL, dPos);
 }
 /* (2)-2若待刪結點右孩子非空,左孩子爲空 */
 else if (NULL == pDelNode->lChild)
 {
  if (pDelNode == pRoot->root)
  {
   pRoot->root = pDelNode->rChild;
  }
  else
  {
   if (LCHILD== dPos)
   {
    pDelParNode->lChild = pDelNode->rChild;
   }
   else
   {
    pDelParNode->rChild = pDelNode->rChild;
   }
  }

  stackPush(pStack, (avlNode_t *)NULL, dPos);
 }
 /* (2)-3若待刪結點左右孩子都非空 */
 else
 {
  /* 這種情況,考慮使用待刪結點的直接前驅或後繼結點替代
  待刪結點。爲減少平衡處理,做一次判斷,用待刪結點平衡
  因子高的一側的鄰近結點替換之 */
  /* (2)-3-1查找鄰近結點,即直接前驅或後繼結點 */
  stackPush(pStack, pDelNode, dPos);  /* 待刪結點再次入棧 */
  switch (pDelNode->bf)
  {
  case LH:
  case EH:
   {
    pTmpNode = pDelNode->lChild;
    stackPush(pStack, pTmpNode, LCHILD);
    do
    {
     pTmpNode = pTmpNode->rChild;
     stackPush(pStack, pTmpNode, RCHILD);
    } while (pTmpNode != NULL); 
    break;
   }
  case RH:
   {
    pTmpNode = pDelNode->rChild;
    stackPush(pStack, pTmpNode, RCHILD);
    do
    {
     pTmpNode = pTmpNode->lChild;
     stackPush(pStack, pTmpNode, LCHILD);
    } while (pTmpNode != NULL); 
    break;
   }
  default:
   {
    ASSERT(0);
    stackFree(&pStack);
    return ERROR;
   }
  }

  /* (2)-3-2找到鄰近結點,用它替換待刪結點 */
  stackPop(pStack, &pTmpNode, &pos);
  stackPop(pStack, &pNearNode, &nPos);  /* 彈出鄰近結點 */
  /* 鄰近結點的左右孩子必定至少有一個爲空,否則不爲待刪
  結點的直接前驅或後繼結點 */
  ASSERT((LCHILD == nPos) || (RCHILD == nPos));
  ASSERT((NULL == pNearNode->lChild) || (NULL == pNearNode->rChild));
  ASSERT(!stackIsEmpty(pStack));
  stackGet(pStack, &pNearParNode, &nParPos);
  ASSERT(pNearParNode != NULL);
  /* (2)-3-2-1摘除pNearNode結點 */
  /* 若鄰近結點的右子樹爲空,或左右皆空 */
  if (NULL == pNearNode->rChild)
  {
   if (LCHILD == nPos)
   {
    pNearParNode->lChild = pNearNode->lChild;
   }
   else
   {
    pNearParNode->rChild = pNearNode->lChild;
   }
  }
  /* 若鄰近結點的右子樹非空,則左子樹必定爲空 */
  else
  {
   if (LCHILD == nPos)
   {
    pNearParNode->lChild = pNearNode->rChild;
   }
   else
   {
    pNearParNode->rChild = pNearNode->rChild;
   }
  }

  /* (2)-3-2-2用pNearNode結點替換pDelNode結點 */
  pNearNode->lChild = pDelNode->lChild;
  pNearNode->rChild = pDelNode->rChild;
  pNearNode->bf = pDelNode->bf;
  if (pDelNode == pRoot->root)
  {
   pRoot->root = pNearNode;
  }
  else
  {
   if (LCHILD == dPos)
   {
    pDelParNode->lChild = pNearNode;
   }
   else
   {
    pDelParNode->rChild = pNearNode;
   }
  }

  /* 記錄鄰近結點位置,用於後續平衡處理 */
  stackPush(pStack, (avlNode_t *)NULL, nPos);
  /* 替換棧中記錄的pDelNode指針爲pNearNode指針,平衡因子保持
  原來pDelNode的bf不變,用於後續平衡處理 */
  stackReplace(pStack, pDelNode, pNearNode);
 }

 /* (2)-4釋放待刪結點 */
 pRoot->count--;
 pRoot->nodeFree(pDelNode);
 pDelNode = NULL;

 /* (3)結點刪除完成,進行平衡處理 */
 /* 彈出刪除或替換結點相應於上級結點的位置關係pos */
 stackPop(pStack, &pTmpNode, &pos);
 if (stackIsEmpty(pStack))
 {
  /* 樹結點小於2時刪除根結點,無需平衡處理 */
  ASSERT(ROOT == pos);
  pRoot->height--;
  stackFree(&pStack);
  return TRUE;
 }
 ASSERT((LCHILD == pos) || (RCHILD == pos));
 
 do
 {
  childPos = pos;
  stackPop(pStack, &pTmpNode, &pos);
  ASSERT(pTmpNode != NULL);
  /* 若刪除或替換結點在pTmpNode左子樹 */
  if (LCHILD == childPos)
  {
   /* 檢查pTmpNode的平衡度 */
   switch (pTmpNode->bf)
   {
   case LH:  /* 原本左子樹比右子樹高,現在等高 */
    {
     pTmpNode->bf = EH;
     if (pTmpNode == pRoot->root)
     {
      pRoot->height--;
     }
     /* 由於該子樹整體高度減低,需向上回溯平衡處理 */
     break;
     
    }
   case EH:  /* 原本左右子樹等高,現因左降低而右高 */
    {
     pTmpNode->bf = RH;
     stackFree(&pStack);
     return TRUE;
    }
   case RH:  /* 原本右子樹比左子樹高,做右平衡處理 */
    {
     /* 根據pTmpNode右孩子的平衡因子情況,判斷平衡
     處理後子樹高度是否降低。僅當pTmpNode的右孩子
     平衡因子爲EH時,以pTmpNode爲根結點平衡處理後
     子樹的高度不變 */
     ASSERT(pTmpNode->rChild != NULL);
     if (pTmpNode->rChild->bf != EH)
     {
      lower = TRUE;
     }
     else
     {
      lower = FALSE;
     }
     
     rightBalance(&pTmpNode);
     /* 平衡處理後,重新連接pTmpNode與父結點關係 */
     if (stackIsEmpty(pStack))
     {
      ASSERT(ROOT == pos);
      pRoot->root = pTmpNode;
     }
     else
     {
      ASSERT((LCHILD == pos) || (RCHILD == pos));
      stackGet(pStack, &pParNode, &parPos);
      ASSERT(pParNode != NULL);
      if (LCHILD == pos)
      {
       pParNode->lChild = pTmpNode;
      }
      else
      {
       pParNode->rChild = pTmpNode;
      }
     }

     if (TRUE == lower)
     {
      if (pTmpNode == pRoot->root)
      {
       pRoot->height--;
      }
      /* 平衡處理後該子樹高度減低,需向上回溯 */
      break;
     }
     else
     {
      stackFree(&pStack);
      return TRUE;
     }
    }
   default:
    {
     ASSERT(0);
     stackFree(&pStack);
     return ERROR;
    }
   }
  }
  /* 若刪除或替換結點在pTmpNode右子樹 */
  else
  {
   ASSERT(RCHILD == childPos);
   switch (pTmpNode->bf)
   {
   case LH:  /* 原本左子樹比右高,作左平衡處理 */
    {
     ASSERT(pTmpNode->lChild != NULL);
     if (pTmpNode->lChild->bf != EH)
     {
      lower = TRUE;
     }
     else
     {
      lower = FALSE;
     }
     
     leftBalance(&pTmpNode);
     /* 平衡處理後,重新連好pTmpNode與父結點的關係 */
     if (stackIsEmpty(pStack))
     {
      ASSERT(ROOT == pos);
      pRoot->root = pTmpNode;
     }
     else
     {
      ASSERT((LCHILD == pos) || (RCHILD == pos));
      stackGet(pStack, &pParNode, &parPos);
      ASSERT(pParNode != NULL);
      if (LCHILD == pos)
      {
       pParNode->lChild = pTmpNode;
      }
      else
      {
       pParNode->rChild = pTmpNode;
      }
     }

     if (TRUE == lower)
     {
      if (pTmpNode == pRoot->root)
      {
       pRoot->height--;
      }
      break;
     }
     else
     {
      stackFree(&pStack);
      return TRUE;
     }
    }
   case EH:  /* 原本左右子樹等高,現因右降低而左高 */
    {
     pTmpNode->bf = LH;
     stackFree(&pStack);
     return TRUE;
    }
   case RH:  /* 原本右子樹比左高,現在等高 */
    {
     pTmpNode->bf = EH;
     if (pTmpNode == pRoot->root)
     {
      pRoot->height--;
     }
     break;
    }
   default:
    {
     ASSERT(0);
     stackFree(&pStack);
     return ERROR;
    }
   }
  }
 } while (!stackIsEmpty(pStack));
 
 stackFree(&pStack);
 return TRUE;
}

/* AVL樹查找函數(非遞歸方法) */
avlNode_t *AVL_find(avlRoot_t *pRoot, avlNode_t *pfindNode)
{
 avlNode_t *pNode = NULL;
 int rtnValue = 0;
 if ((NULL == pRoot) || (NULL == pfindNode))
 {
  ASSERT(0);
  return NULL;
 }

 pNode = pRoot->root;
 while (pNode != NULL)
 {
  rtnValue = pRoot->nodeCmp(pfindNode, pNode);
  if (0 == rtnValue)
  {
   break;
  }

  if (rtnValue < 0)
  {
   pNode = pNode->lChild;
  }
  else
  {
   pNode = pNode->rChild;
  }
 }

 return pNode;
}

/* AVL樹查找函數(遞歸方法) */
avlNode_t *AVL_find_R(avlNode_t *pNode, avlNode_t *pfindNode)
{
 if ((NULL == pNode) || (NULL == pfindNode))
 {
  return NULL;
 }

 if (0 == nodeCmp(pfindNode, pNode))
 {
  return pNode;
 }

 if (nodeCmp(pfindNode, pNode) < 0)
 {
  return AVL_find_R(pNode->lChild, pfindNode);
 }
 else
 {
  return AVL_find_R(pNode->rChild, pfindNode);
 }
}

/* 由當前結點數據查找其父結點(非遞歸方法) */
avlNode_t *AVL_findParent(avlRoot_t *pRoot, avlNode_t *pNode)
{
 stack_t *pStack = NULL;
 avlNode_t *pTmpNode = NULL;
 pos_e pos = ROOT;
 if (NULL == pRoot)
 {
  ASSERT(0);
  return NULL;
 }

 pTmpNode = pRoot->root;
 stackInit(&pStack); 
 while((pTmpNode != NULL) || (!stackIsEmpty(pStack)))
 {
  if (pTmpNode != NULL)
  {
   stackPush(pStack, pTmpNode, pos);
   pTmpNode = pTmpNode->lChild;
  }
  else
  {
   stackPop(pStack, &pTmpNode, &pos);
   pTmpNode = pTmpNode->rChild;
  }

  if ((pTmpNode != NULL) && (0 == pRoot->nodeCmp(pTmpNode, pNode)))
  {
   break;
  }
 }
 stackPop(pStack, &pTmpNode, &pos);  /* 彈出父結點指針 */
 stackFree(&pStack);

 return pTmpNode;
}

/* AVL樹中序遍歷函數 */
void AVL_traverseInOrder(avlRoot_t *pRoot)
{
 stack_t *pStack = NULL;
 avlNode_t *pNode = NULL;
 pos_e pos = ROOT;
 if (NULL == pRoot)
 {
  ASSERT(0);
  return;
 }

 pNode = pRoot->root;
 stackInit(&pStack);
 printf("Count:%13d\nHeight:%12d\n", pRoot->count, pRoot->height);
 while ((pNode != NULL) || (!stackIsEmpty(pStack)))
 {
  while (pNode != NULL)
  {
   stackPush(pStack, pNode, pos);
   pNode = pNode->lChild;
  }
  stackPop(pStack, &pNode, &pos);
  pRoot->nodePrint(pNode);
  pNode = pNode->rChild;
 }
 printf("\n");
 stackFree(&pStack);

 return;
}

/* 釋放AVL樹函數,包括根結點和數據結點,從左側底開始釋放 */
void AVL_free(avlRoot_t **ppRoot)
{
 stack_t *pStack = NULL;
 avlNode_t *pNode = NULL;
 avlNode_t *pParNode = NULL;
 pos_e pos = ROOT;
 if ((NULL == *ppRoot) || (NULL == ppRoot))
 {
  ASSERT(0);
  return;
 }

 pNode = (*ppRoot)->root;
 stackInit(&pStack); 
 while ((pNode != NULL) || (!stackIsEmpty(pStack)))
 {
  while (pNode != NULL)
  {
   stackPush(pStack, pNode, pos);
   pNode = pNode->lChild;
  }
  stackPop(pStack, &pNode, &pos);
  ASSERT(pNode != NULL);
  
  if (pNode->rChild != NULL)
  {
   stackPush(pStack, pNode, pos);
   pNode = pNode->rChild;
   continue;
  }
  
  /* 樹結點的左右孩子都空,釋放之 */
  if (!stackIsEmpty(pStack))  /* 樹的非根結點釋放 */
  {
   stackPop(pStack, &pParNode, &pos);
   if (pParNode->lChild == pNode)
   {
    pParNode->lChild = NULL;
   }
   else
   {
    pParNode->rChild = NULL;
   }
   (*ppRoot)->nodeFree(pNode);
   pNode = pParNode;
  }
  else                        /* 樹的根結點釋放 */
  {
   ASSERT(((*ppRoot)->root == pNode) && stackIsEmpty(pStack));
   (*ppRoot)->nodeFree(pNode);
   pNode = NULL;
   (*ppRoot)->root = NULL;
  }
 }
 //(*ppRoot)->count = 0;

 /* 釋放完所有樹結點,最後釋放Root結點 */
 free(*ppRoot);
 *ppRoot = NULL;
 stackFree(&pStack);

 return;
}

/* 封裝avl樹結點,並初始化結點數據 */
avlNode_t *encapNode(key_t *key)
{
 myAvlNode_t *pNode = NULL;
 if (NULL == key)
 {
  ASSERT(0);
  return NULL;
 }

 pNode = (myAvlNode_t *)malloc(sizeof(myAvlNode_t));
 if (NULL == pNode)
 {
  ASSERT(0);
  return NULL;
 }
 //pNode->prev = NULL;
 //pNode->next = NULL;
 pNode->lChild = NULL;
 pNode->rChild = NULL;
 pNode->bf = EH;
 memcpy(&(pNode->key), key, sizeof(key_t));
 //data encap

 return (avlNode_t *)pNode;
}

/* AVL樹結點鍵值比較函數 */
int nodeCmp(avlNode_t *pNode1, avlNode_t *pNode2)
{
 myAvlNode_t *pMyNode1 = (myAvlNode_t *)pNode1;
 myAvlNode_t *pMyNode2 = (myAvlNode_t *)pNode2;
 int rtnValue = 0; 
 if ((NULL == pNode1) || (NULL == pNode2))
 {
  ASSERT(0);
  return ERROR;
 }

 rtnValue = (pMyNode1->key == pMyNode2->key) ? \
  0 : ((pMyNode1->key > pMyNode2->key) ? 1 : (-1));

 return rtnValue;
}

/* AVL樹結點內存釋放函數 */
void nodeFree(avlNode_t *pNode)
{
 myAvlNode_t *pMyNode = (myAvlNode_t *)pNode;
 if (NULL == pNode)
 {
  ASSERT(0);
  return;
 }

 free(pMyNode);

 return;
}

/* AVL樹結點數據打印函數 */
void nodePrint(avlNode_t *pNode)
{
 myAvlNode_t *pMyNode = (myAvlNode_t *)pNode;
 if (NULL == pNode)
 {
  ASSERT(0);
  return;
 }

 printf("%d\t", pMyNode->key);

 return;
}

/****************************************************************/
/************************ 棧的相關函數 **************************/

/* 棧初始化函數 */
static void stackInit(stack_t **ppStack)
{
 if (NULL == ppStack)
 {
  ASSERT(0);
  return;
 }
 
 *ppStack = (stack_t *)malloc(sizeof(stack_t));
 if (NULL == *ppStack)
 {
  ASSERT(0);
  return;
 }
 memset((char *)(*ppStack), 0, sizeof(stack_t));

 return;
}

/* 壓棧函數 */
static void stackPush(stack_t *pStack, avlNode_t *pNode, pos_e pos)
{
 if (NULL == pStack)
 {
  ASSERT(0);
  return;
 }
 if (STACK_SIZE == pStack->top)
 {
  printf("stackPush:Stack is full!\n");
  return;
 }

 (pStack->buff)[pStack->top] = pNode;
 (pStack->pos)[pStack->top] = pos;
 pStack->top++;

 return;
}

/* 出棧函數 */
static void stackPop(stack_t *pStack, avlNode_t **pNode, pos_e *pPos)
{
 if ((NULL == pStack) || (NULL == pNode) || (NULL == pPos))
 {
  ASSERT(0);
  return;
 }
 if (0 == pStack->top)
 {
  printf("stackPop:Stack is empty!\n");
  return;
 }

 pStack->top--;
 *pNode = (pStack->buff)[pStack->top];
 *pPos = (pStack->pos)[pStack->top];
 
 return;
}

/* 取棧頂元素函數 */
static void stackGet(stack_t *pStack, avlNode_t **pNode, pos_e *pPos)
{
 if ((NULL == pStack) || (NULL == pNode) || (NULL == pPos))
 {
  ASSERT(0);
  return;
 }
 if (0 == pStack->top)
 {
  printf("stackPop:Stack is empty!\n");
  return;
 }

 *pNode = (pStack->buff)[pStack->top - 1];
 *pPos = (pStack->pos)[pStack->top - 1];
 
 return;
}

/* 判棧是否爲空:若空返回TRUE,非空返回FALSE */
static BOOL stackIsEmpty(stack_t *pStack)
{
 if (NULL == pStack)
 {
  ASSERT(0);
  return FALSE;
 }
 
 return (0 == pStack->top) ? TRUE : FALSE;
}

/* 棧元素替換函數 */
static void stackReplace(stack_t *pStack, avlNode_t *pInitNode, avlNode_t *pRepNode)
{
 int idx = 0;
 if (NULL == pStack)
 {
  ASSERT(0);
  return;
 }

 for (idx = pStack->top; idx >= 0; idx --)
 {
  if (pInitNode == (pStack->buff)[idx])
  {
   (pStack->buff)[idx] = pRepNode;
   break;
  }
 }

 return;
}

/* 棧內存釋放函數 */
static void stackFree(stack_t **ppStack)
{
 if ((NULL == ppStack) || (NULL == *ppStack))
 {
  ASSERT(0);
  return;
 }

 free(*ppStack);
 *ppStack = NULL;

 return;
}

/****************************************************************/
/* ************************* The End ************************** */



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章