AVL樹在ROS系統中應用廣泛,如路由表管理模塊和FEC表,這些大容量又操作頻繁的數據,採用AVL樹存儲結構可以有效提高系統效率。
AVL樹又稱爲高度平衡的二叉搜索樹(BST),是1962年由兩位俄羅斯數學家G.M.Adel’ son-Vel'sky和E.M.Landis在論文《An algorithm for theorganization of information》中提出的。引入它的目的,是爲了提高BST的搜索效率,即減少平均搜索長度。爲此,向BST中每插入或刪除一個新結點時,就必須調整樹的結構,使得BST繼續保持平衡,從而儘可能降低樹的高度。
下面先講講AVL樹的一些基本概念:
AVL樹的定義:一棵ALV樹或者是空樹,或者是具有下列性質的二叉搜索樹:它的左子樹和右子樹都是AVL樹,且左子樹和右子樹的高度之差的絕對值不超過1。
AVL樹的高度:(固定節點數計算最大高度)
記N(h)爲一棵高度爲h的AVL樹具有的最小節點數,則最壞情況是它的左右子樹的高度不等,即一個是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,-1或0
一、如果路徑上節點平衡因子是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情況類似,旋轉後只需再次改變兩個節點的平衡因子
如下圖爲RL的情況,LR類似,旋轉後需要再次改變三個節點的平衡因子
至此,插入操作已經完成,可見最多多做兩次旋轉操作調整樹的結構使之平衡。
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爲例,稱A爲L不平衡
如果A的右節點的平衡因子是0,則進行一次左旋轉,如圖:
由於子樹的高度和刪除前一樣,因此樹已經平衡。
如果A的右節點的平衡因子是-1,則稱爲L-1不平衡,也要進行一次做旋轉。
樹的高度減少1,這使得上面的祖先節點可能不平衡,一次還要沿着路徑在向上
尋找新的不平衡點,再次更新平衡因子,調整等。
如果A的右節點的平衡因子是1,則稱爲L1不平衡,要進行兩次旋轉。
此時要根據BL的情況決定A和B的新的平衡因子。
由於樹的高度減少了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 ************************** */