數據結構--Avl樹的創建,插入的遞歸版本和非遞歸版本,刪除等操作
阿新 • • 發佈:2017-05-03
pop end eem static cout 遞歸 sta div else
AVL樹本質上還是一棵二叉搜索樹,它的特點是:
1.本身首先是一棵二叉搜索樹。 2.帶有平衡條件:每個結點的左右子樹的高度之差的絕對值最多為1(空樹的高度為-1)。 也就是說,AVL樹,本質上是帶了平衡功能的二叉查找樹(二叉排序樹,二叉搜索樹)。 對Avl樹進行相關的操作最重要的是要保持Avl樹的平衡條件。即對Avl樹進行相關的操作後,要進行相應的旋轉操作來恢復Avl樹的平衡條件。 對Avl樹的插入和刪除都可以用遞歸實現,文中也給出了插入的非遞歸版本,關鍵在於要用到棧。 代碼如下:#include <iostream> #include<stack> using namespace std; struct AvlNode; typedef struct AvlNode *Position; typedef struct AvlNode *Avltree; struct AvlNode //AVL樹節點 { int Element; Avltree Left; Avltree Right; int Hight; int Isdelete; //指示該元素是否被刪除 }; ///////////////AVL平衡樹的函數的相關聲明////////////////////// Avltree MakeEmpty(Avltree T); //清空一棵樹 static int Height(Position P); //返回節點的高度 Avltree Insert(int x, Avltree T); //在樹T中插入元素x Avltree Insert_not_recursion (int x, Avltree T); //在樹T中插入元素x,非遞歸版本 Position FindMax(Avltree T); //查找Avl樹的最大值,和二叉樹一樣 Avltree Delete(int x,Avltree T); //刪除元素,非懶惰刪除 ///////////////AVL平衡樹的函數的相關定義////////////////////// Avltree MakeEmpty(Avltree T) { if (T != NULL) { MakeEmpty(T->Left); MakeEmpty(T->Right); delete T;// free(T); } return NULL; } static int Height(Position P) //返回節點的高度 { if(P == NULL) return -1; else return P->Hight; } static int Element(Position P) //返回節點的元素 { if(P == NULL) return -1000; else return P->Element; } int Max(int i,int j) //返回最大值 { if(i > j) return i; else return j; } static Position SingleRotateWithLeft (Position k2) //單旋轉,左子樹高度比較高 { Position k1; k1 = k2->Left; k2->Left = k1->Right; k1->Right = k2; k2->Hight = Max(Height(k2->Left), Height(k2->Right)) + 1; k1->Hight = Max(Height(k1->Left), Height(k1->Right)) + 1; return k1; //新的根 } static Position SingleRotateWithRight (Position k1) //單旋轉,右子樹的高度比較高 { Position k2; k2 = k1->Right; k1->Right = k2->Left; k2->Left = k1; k1->Hight = Max(Height(k1->Left), Height(k1->Right)) + 1; k2->Hight = Max(Height(k2->Left), Height(k2->Right)) + 1; return k2; //新的根 } static Position DoubleRotateWithLeft (Position k3) //雙旋轉,當k3有左兒子而且k3的左兒子有右兒子 { k3->Left = SingleRotateWithRight(k3->Left); return SingleRotateWithLeft(k3); } static Position DoubleRotateWithRight (Position k1) //雙旋轉,當k1有右兒子而且k1的又兒子有左兒子 { k1->Right = SingleRotateWithLeft(k1->Right); return SingleRotateWithRight(k1); } //對Avl樹執行插入操作,遞歸版本 Avltree Insert(int x, Avltree T) { if(T == NULL) //如果T為空樹,就創建一棵樹,並返回 { T = static_cast<Avltree>(malloc(sizeof(struct AvlNode))); if (T == NULL) { cout << "out of space!!!" << endl; } else { T->Element = x; T->Left = NULL; T->Right = NULL; T->Hight = 0; T->Isdelete = 0; } } else //如果不是空樹 { if(x < T->Element) { T->Left = Insert(x,T->Left); if(Height(T->Left) - Height(T->Right) == 2 ) { if(x < T->Left ->Element ) T = SingleRotateWithLeft(T); else T = DoubleRotateWithLeft(T); } } else { if(x > T->Element ) { T->Right = Insert(x,T->Right ); if(Height(T->Right) - Height(T->Left) == 2 ) { if(x > T->Right->Element ) T = SingleRotateWithRight(T); else T = DoubleRotateWithRight(T); } } } } T->Hight = Max(Height(T->Left), Height(T->Right)) + 1; return T; } //對Avl樹進行插入操作,非遞歸版本 Avltree Insert_not_recursion (int x, Avltree T) { stack<Avltree> route; //定義一個堆棧使用 //找到元素x應該大概插入的位置,但是還沒進行插入 Avltree root = T; while(1) { if(T == NULL) //如果T為空樹,就創建一棵樹,並返回 { T = static_cast<Avltree>(malloc(sizeof(struct AvlNode))); if (T == NULL) cout << "out of space!!!" << endl; else { T->Element = x; T->Left = NULL; T->Right = NULL; T->Hight = 0; T->Isdelete = 0; route.push (T); break; } } else if (x < T->Element) { route.push (T); T = T->Left; continue; } else if (x > T->Element) { route.push (T); T = T->Right; continue; } else { T->Isdelete = 0; return root; } } //接下來進行插入和旋轉操作 Avltree father,son; while(1) { son = route.top (); route.pop(); //彈出一個元素 if(route.empty()) return son; father = route.top (); route.pop(); //彈出一個元素 if(father->Element < son->Element ) //兒子在右邊 { father->Right = son; if( Height(father->Right) - Height(father->Left) == 2) { if(x > Element(father->Right)) father = SingleRotateWithRight(father); else father = DoubleRotateWithRight(father); } route.push(father); } else if (father->Element > son->Element) //兒子在左邊 { father->Left = son; if(Height(father->Left) - Height(father->Right) == 2) { if(x < Element(father->Left)) father = SingleRotateWithLeft(father); else father = DoubleRotateWithLeft(father); } route.push(father); } father->Hight = max(Height(father->Left),Height(father->Right )) + 1; } } Position FindMax(Avltree T) { if(T != NULL) { while(T->Right != NULL) { T = T->Right; } } return T; } Position FindMin(Avltree T) { if(T == NULL) { return NULL; } else { if(T->Left == NULL) { return T; } else { return FindMin(T->Left ); } } } Avltree Delete(int x,Avltree T) //刪除Avl樹中的元素x { Position Temp; if(T == NULL) return NULL; else if (x < T->Element) //左子樹平衡條件被破壞 { T->Left = Delete(x,T->Left ); if(Height(T->Right) - Height(T->Left) == 2) { if(x > Element(T->Right) ) T = SingleRotateWithRight(T); else T = DoubleRotateWithRight(T); } } else if (x > T->Element) //右子樹平衡條件被破壞 { T->Right = Delete(x,T->Right ); if(Height(T->Left) - Height(T->Right) == 2) { if(x < Element(T->Left) ) T = SingleRotateWithLeft(T); else T = DoubleRotateWithLeft(T); } } else //執行刪除操作 { if(T->Left && T->Right) //有兩個兒子 { Temp = FindMin(T->Right); T->Element = Temp->Element; T->Right = Delete(T->Element ,T->Right); } else //只有一個兒子或者沒有兒子 { Temp = T; if(T->Left == NULL) T = T->Right; else if(T->Right == NULL) T = T->Left; free(Temp); } } return T; } int main () { Avltree T = NULL; T = Insert_not_recursion(3, T); //T一直指向樹根 T = Insert_not_recursion(2, T); T = Insert_not_recursion(1, T); T = Insert_not_recursion(4, T); T = Insert_not_recursion(5, T); T = Delete(1,T); // T = Insert_not_recursion(6, T); /* T = Insert(3, T); //T一直指向樹根 T = Insert(2, T); T = Insert(1, T); T = Insert(4, T); T = Insert(5, T); T = Insert(6, T);*/ cout << T->Right->Right->Element << endl; return 0; }
遞歸與棧的使用有著不可描述的關系,我覺得如果要把遞歸函數改寫成非遞歸的函數,首先要想到用棧。
唉,夜似乎更深了。
數據結構--Avl樹的創建,插入的遞歸版本和非遞歸版本,刪除等操作