AVL樹的基本操作之插入(遞迴與非遞迴編碼)(2)
阿新 • • 發佈:2019-01-27
摘要:(1)插入的基本思路;首先遞迴的插入,插入完成之後,逐個返回,對於返回的每一個節點都要檢查,是否該次插入是使得這個節點不平衡。為了簡化程式碼,定義一個Height()函式,用來處理該節點為NULL的情況。當該節點不平衡時,就要進行旋轉。根據插入元素與該節點元素兒子的大小關係可以確定旋轉型別。
(2)非遞迴程式設計有一點麻煩:基本思路還是用一個棧來保留經過的節點。
int Height(Position T)//獲得高度
{
if (T==NULL)
return -1;
else
return T->Height;
}
int Max (int x,int y)//返回一個較大值
{
if (x == y)
return x;
else
return x>y?x:y;
}
Position InsertAvl(Position T,int X)//遞迴演算法
{
if (T == NULL)
{
T = (Position)malloc(sizeof(AvlTreeRecord));
T->Element = X;
T->Height = 0;
T->Left = NULL;
T-> Right = NULL;
}
else
//
{
if (X >T->Element)
{
T->Right = InsertAvl(T->Right,X);
if (Height(T->Right)-Height(T->Left) == 2){//需要調整
if (X > T->Right->Element)
T = SingleRotateRight(T);
else
T = DoubleRotateRight(T);
}
}
else if (X< T->Element)
{
T->Left = InsertAvl(T->Left,X);
if(Height(T->Left)-Height(T->Right) == 2){//需要調整
if (X < T->Left->Element)
T = SingleRotateLeft(T);
else
T = DoubleRotateLeft(T);
}
}
T->Height = Max(Height(T->Left),Height(T->Right))+1;
return T;
}
}
Position Insert_noninduction(int X,Position T)
{
int mark1,mark2;
Position Temp = T;
List L,P;
L = (List)malloc(sizeof(ListRecord));
L->mark = -1;
P = L->Next;
if (T == NULL)
{
//直接插入
T = Create(X);
return T;
}
while(1)
{
if (X > T->Element)//進入右子樹
{
//連結串列記錄
L->Next = CreateList(T);
L->Next->Previous = L;
L = L->Next;
L->mark = Rtree;
if (T->Right == NULL)
{
T->Right = Create(X);
break;
}
else
T = T->Right;
}
else //進入左子樹
{
//連結串列記錄
L->Next = CreateList(T);
L->Next->Previous = L;
L = L->Next;
L->mark = Ltree;
if (T->Left == NULL)
{
T->Left = Create(X);
break;
}
else
T = T->Left;
}
}//while
P = L;//儲存最後的節點,方便確定旋轉
while(L->mark!=-1)
{
//從葉子向上計算插入路徑上節點的高度
L->Pointer->Height = Max(Height(L->Pointer->Left),Height(L->Pointer->Right))+1;
L = L->Previous;
}
L = P;//將L恢復到插入節點的父節點
//進行判斷是否旋轉以及進行節點連線
do
{
if (abs(Height(L->Pointer->Left) - Height(L->Pointer->Right)) == 2)
{
T = L->Pointer;
mark1 = L->mark;
mark2 = L->Next->mark;
switch (mark1)
{
//確定進行哪種調整
case Rtree:
if (mark2 == Rtree)
T = SingleRotateRight(T);
else
T = DoubleRotateRight(T);
break;
case Ltree:
if (mark2 == Ltree)
T = SingleRotateLeft(T);
else
T = DoubleRotateLeft(T);
break;
}
//用來確定旋轉後與父節點的連結方式
if (L->Previous->mark != -1)
{
switch(L->Previous->mark)
{
case Rtree:
L->Previous->Pointer->Right = T;
break;
case Ltree:
L->Previous->Pointer->Left = T;
}
}
else
//root 是調整點,無需與父節點連結.
Temp = T;
}
L = L->Previous;
} while(L->mark != -1);
return Temp;
}