歡迎探討,如有錯誤敬請指正
如需轉載,請注明出處http://www.cnblogs.com/nullzx/
1. AVL定義
AVL樹是一種改進版的搜索二叉樹。對於一般的搜索二叉樹而言,如果數據恰好是按照從小到大的順序或者從大到小的順序插入的,那么搜索二叉樹就對退化成鏈表,這個時候查找,插入和刪除的時間都會上升到O(n),而這對於海量數據而言,是我們無法忍受的。即使是一顆由完全隨機的數據構造成的搜索二叉樹,從統計角度去分析,在進行若甘次的插入和刪除操作,這個搜索二叉樹的高度也不能令人滿意。這個時候大家就希望能有一種二叉樹解決上述問題。這個時候就出現平衡搜索二叉樹,它的基本原理就是在插入和刪除的時候,根據情況進行調整,以降低二叉樹的高度。平衡搜索二叉樹典型代表就是AVL樹和紅黑樹。
AVL樹:任何一個節點的左子支高度與右子支高度之差的絕對值不超過1。需要我們注意的是,AVL樹定義不是說從根節點到葉子節點的最短距離比最長短距離大1。
上圖就是一顆AVL樹,從根節點到葉子節點的最短距離是5,最長距離是9。
2. 旋轉的定義
因為每種書中對旋轉的定義不一致,所以我們有必要在這里特此說明一下
以某一個節點為軸,它的左子枝順時針旋轉,作為新子樹的根,我們稱之為順時針旋轉(clockwise)或者右旋轉。
同理,以某一個節點為軸,它的右子枝逆針旋轉,作為新子樹的根,我們稱之為逆時針旋轉(anticlockwise)或者左旋轉。
3. AVL插入操作
AVL樹的插入操作首先會按照普通搜索二叉樹的插入操作進行,當插入一個數據后,我們會沿着插入數據時所經過的的節點回溯,回溯的過程中會判回溯路徑中的每個節點的左子支高度與右子支高度之差的絕對值是否超過1,如果超過1我們就進行調整,調整的目的是使得該節點滿足AVL樹的定義。調整的情況可以分為以下四旋轉操作,旋轉操作可以降低樹的高度,同時不改變搜索二叉樹的性質(即任何一個節點左子支中的全部節點小於該節點,右子支的全部節點大於該節點)。
3.1 情況1
節點X左子支比右子支高度大2,且插入的節點位於X的左孩子節點XL的左子支上
3.2 情況2
節點X右子支比左子支高度大2,且插入的節點位於節點X右孩子節點XR的右子支上
3.3 情況3
節點X左子支比右子支高度大2,且插入的節點位於節點X左孩子節點XL的右子支上
3.4 情況4
節點X左子支比右子支高度大2,且插入的節點位於節點X左孩子節點XL的右子支上
4. AVL刪除操作
AVL樹的刪除操作和插入操作一樣,首先會按照普通搜索二叉樹的刪除操作進行,當刪除一個數據后,和插入操作一樣,我們通常采取的策略是沿着刪除數據時所經過的的節點回溯,回溯的過程中會判斷該節點的左子支高度與右子支高度之差的絕對值是否超過1(或者說大2),如果超過1,我們就進行調整,調整的目的是使得該節點滿足AVL樹的定義。調整的情況可以分為四種,和插入過程完全一樣,這里不在贅述。
5. C語言實現
5.1節點定義
AVLtree.h文件中的內容
#ifndef __AVLTREE_H__ #define __AVLTREE_H__ typedef struct Node{ int height; //該節點作為子樹時的高度 int data; //表示每個節點存貯的數據 Node* left; Node* right; }Node, *AVLtree; //AVLtree 表示Node* //AVLtree* 就表示Node** int Insert(AVLtree* T, int D); int Delete(AVLtree* T, int D); int Find(AVLtree T, int x); int Destroy(AVLtree* T); //下面兩個遍歷函數主要用於測試 void InOredrTraverse(AVLtree T); void PreOredrTraverse(AVLtree T); #endif
5.2代碼實現
AVLtree.cpp文件中的內容
#include"AVLtree.h" #include<stdlib.h> #include<stdio.h> #define MAX(x1,x2) ((x1) > (x2) ? (x1) : (x2)) //一下函數用於輔助實現插入刪除操作,作用域於僅限於AVLtree.cpp static void PostOrderTraverse(AVLtree T); static int GetHeight(AVLtree T); static void LeftRotate(AVLtree* T); static void RightRotate(AVLtree* T); static int FindMin(AVLtree T); //返回值用於表示插入是否成功,-1表示失敗(說明樹中已包含該數據),0表示成功 int Insert(AVLtree* T,int D){ //參數檢查 if(T == NULL){ return -1; } //找到插入的位置 if(*T == NULL){ *T = (Node*)malloc(sizeof(Node)); (*T)->data = D; (*T)->height = 1; (*T)->left = NULL; (*T)->right = NULL; return 0; }else{ //樹中已存在該數據 if(D == (*T)->data){ return -1; }else if(D > (*T)->data){//在右子樹中插入 if(Insert(&(*T)->right,D) == -1){ return -1; } //插入后,當回溯到該節點進行檢查,如果不滿足平衡條件,則調整 //因為是在右子支中插入,如果高度只差等於2,只可能是右子支比左子支高 if(GetHeight((*T)->right) - GetHeight((*T)->left) == 2){ if(D > (*T)->right->data){ LeftRotate(T);//對應情況2,左旋 }else{//對應情況4,先右旋再左旋 RightRotate(&(*T)->right); LeftRotate(T); } } }else if(D < (*T)->data){//在左子樹中插入 if(Insert(&(*T)->left,D)){ return -1; } if(GetHeight((*T)->left) - GetHeight((*T)->right) == 2){ if(D < (*T)->left->data){ RightRotate(T);//對應情況1,左旋 }else{//對應情況3,先右旋再左旋 LeftRotate(&(*T)->left); RightRotate(T); } } } } //更新當前節點的高度 (*T)->height = MAX(GetHeight((*T)->left),GetHeight((*T)->right))+1; return 0; } //返回-1表示,樹中沒有該數據,刪除失敗, int Delete(AVLtree* T,int D){ static Node* tmp; if(T == NULL){ return -1; } if(*T == NULL){//樹為空,或者樹中沒有該數據 return -1; }else{ //找到要刪除的節點 if(D == (*T)->data){ //刪除的節點左右子支都不為空,一定存在前驅節點 if((*T)->left != NULL && (*T)->right != NULL){ D = FindMin((*T)->right);//找后繼替換 (*T)->data = D; Delete(&(*T)->right,D);//然后刪除后繼節點,一定成功 //在右子支中刪除,刪除后有可能左子支比右子支高度大2 if(GetHeight((*T)->left)-GetHeight((*T)->right) == 2){ //判斷哪一個左子支的的兩個子支哪個比較高 if(GetHeight((*T)->left->left) >= GetHeight((*T)->left->right)){ RightRotate(T); }else{ LeftRotate(&(*T)->left); RightRotate(T); } } }else if((*T)->left == NULL){//左子支為空 tmp = (*T); (*T) = tmp->right; free(tmp); return 0; }else if((*T)->right == NULL){//右子支為空 tmp = (*T); (*T) = tmp->left; free(tmp); return 0; } }else if(D > (*T)->data){//在右子支中尋找待刪除的節點 if(Delete(&(*T)->right,D) == -1){ return -1;//刪除失敗,不需要調整,直接返回 } if(GetHeight((*T)->left)-GetHeight((*T)->right) == 2){ if(GetHeight((*T)->left->left) >= GetHeight((*T)->left->right)){ RightRotate(T); }else{ LeftRotate(&(*T)->left); RightRotate(T); } } }else if(D < (*T)->data){//在左子支中尋找待刪除的節點 if(Delete(&(*T)->left,D) == -1){ return -1; } if(GetHeight((*T)->right) - GetHeight((*T)->left) == 2){ if(GetHeight((*T)->right->right) >= GetHeight((*T)->right->left)){ LeftRotate(T); }else{ RightRotate(&(*T)->right); LeftRotate(T); } } } } //更新當前節點的高度 (*T)->height = MAX(GetHeight((*T)->left),GetHeight((*T)->right))+1; return 0; } int Find(AVLtree T,int x){ while(T != NULL){ if(T->data == x){ return 0; }else if(x > T->data){ T = T->right; }else{ T = T->left; } } return -1; } int Destroy(AVLtree* T){ if(T == NULL){ return -1; } PostOrderTraverse(*T); *T = NULL; return 0; } void InOredrTraverse(AVLtree T){ if(T != NULL){ InOredrTraverse(T->left); printf("%3d ",T->data); InOredrTraverse(T->right);; } } void PreOredrTraverse(AVLtree T){ if(T != NULL){ printf("%3d:%2d(%3d,%3d)\n",T->data,T->height, T->left == NULL?-1:T->left->data, T->right == NULL?-1:T->right->data ); PreOredrTraverse(T->left); PreOredrTraverse(T->right); } } static void PostOrderTraverse(AVLtree T){ if(T != NULL){ PostOrderTraverse(T->left); PostOrderTraverse(T->right); free(T); } } //空數的高度為0 static int GetHeight(AVLtree T){ if(T == NULL){ return 0; }else{ return T->height; } } static void LeftRotate(AVLtree* T){ Node *P,*R; P = *T; R = P->right; P->right = R->left; R->left = P; *T = R; //旋轉以后要更新節點的高度 P->height = MAX(GetHeight(P->left),GetHeight(P->right))+1; R->height = MAX(GetHeight(R->left),GetHeight(R->right))+1; } static void RightRotate(AVLtree* T){ Node *P,*L; P = *T; L = P->left; P->left = L->right; L->right = P; *T = L; //旋轉以后要更新節點的高度 P->height = MAX(GetHeight(P->left),GetHeight(P->right))+1; L->height = MAX(GetHeight(L->left),GetHeight(L->right))+1; } static int FindMin(AVLtree T){ if(T == NULL){ return -1; } while(T->left != NULL){ T = T->left; } return T->data; }
6. Java語言泛型實現
package datastruct; import java.util.Comparator; public class AVLtree <E>{ private static class Node<E>{ int h; E element; Node<E> left; Node<E> right; //由於java中不像C語言那樣有二級指針的概念,所以添加一個父類的引用,方便程序編寫 Node<E> parent; public Node(E element, int h, Node<E> left, Node<E> right, Node<E> parent){ this.element = element; this.h = h; this.left = left; this.right = right; this.parent = parent; } } private Node<E> root;//指向偽根節點的引用 private int size = 0;//節點個數 Comparator<? super E> cmp;//節點大小的比較器 //如果調用了不帶參數的構造函數,則使用該內部類作為比較器, //但此時泛型E需要繼承Comparable接口,否則運行時會拋出異常 private static class Cmp<T> implements Comparator<T>{ @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public int compare(T e1, T e2) { return ((Comparable)e1).compareTo(e2); } } //帶比較器的構造函數 public AVLtree(Comparator<? super E> cmp){ if(cmp == null){ throw new IllegalArgumentException(); } this.cmp = cmp; //創建一個偽根節點,該節點的右子支才是真正的AVL樹的根 //使用偽根節點節點的目的是,對插入和刪除操作遞歸的形式能夠統一 root = new Node<E>(null, -1, null, null, null); } //不帶比較器的構造函數 public AVLtree(){ this.cmp = new Cmp<E>(); root = new Node<E>(null, -1, null, null, null); } //如果樹中節點有變動,從底向上逐級調用該函數,可以更新節點的高度 private int getHight(Node<E> x){ if(x == null){ return 0; }else{ return x.h; } } //求某個節點作為根時,該子樹的最小值 private E treeMin(Node<E> x){ while(x.left != null){ x = x.left; } return x.element; } public int size(){ return size; } //先根遍歷,調試時使用 public void preorderTraverse(){ if(root != null){ preorderTraverse0(root.right); } } private void preorderTraverse0(Node<E> x){ if(x != null){ System.out.print(x.element+" "); if(x.left != null){ System.out.print(x.left.element+" "); }else{ System.out.print("null "); } if(x.right != null){ System.out.print(x.right.element+" "); }else{ System.out.print("null "); } System.out.println(); preorderTraverse0(x.left); preorderTraverse0(x.right); } } //逆時針旋轉(左旋),參數表示軸節點 private void antiClockwiseRotate(Node<E> X){ Node<E> P = X.parent; Node<E> XR = X.right; if(P.left == X){ P.left = XR; }else{ P.right = XR; } XR.parent = P; X.right = XR.left; if(XR.left != null){ XR.left.parent = X; } XR.left = X; X.parent = XR; //旋轉后要更新這兩個節點的高度 X.h = Math.max(getHight(X.left), getHight(X.right)) + 1; XR.h = Math.max(getHight(XR.left), getHight(XR.right)) + 1; } //順時針旋轉(右旋),參數表示軸節點 private void clockwistRotate(Node<E> X){ Node<E> P = X.parent; Node<E> XL = X.left; if(P.left == X){ P.left = XL; }else{ P.right = XL; } XL.parent = P; X.left = XL.right; if(XL.right != null){ XL.right.parent = X; } XL.right = X; X.parent = XL; //旋轉后要更新這兩個節點的高度 X.h = Math.max(getHight(X.left), getHight(X.right)) + 1; XL.h = Math.max(getHight(XL.left), getHight(XL.right)) + 1; } // public void insert(E e){ insert0(root.right, e); } private void insert0(Node<E> x, E e){ if(x == null){ root.right = new Node<E>(e, 1, null, null, root);//根節點 size++; return; } if(cmp.compare(e, x.element) > 0){ if(x.right != null){ insert0(x.right, e); int lh = getHight(x.left); int rh = getHight(x.right); if(rh - lh == 2){ if(cmp.compare(e, x.right.element) > 0){ antiClockwiseRotate(x); }else{ clockwistRotate(x.right); antiClockwiseRotate(x); } } }else{ size++; x.right = new Node<E>(e, 1, null, null, x); } }else if(cmp.compare(e, x.element) < 0){ if(x.left != null){ insert0(x.left, e); int lh = getHight(x.left); int rh = getHight(x.right); if(lh - rh == 2){ if(cmp.compare(e, x.left.element) < 0){ clockwistRotate(x); }else{ antiClockwiseRotate(x.left); clockwistRotate(x); } } }else{ size++; x.left = new Node<E>(e, 1, null, null, x); } }else{ //元素已存在,我們用新的元素更新舊, //compare返回值等於0,並不表示兩個對象完全相等 x.element = e; } x.h = Math.max(getHight(x.left), getHight(x.right)) + 1; } public boolean delete(E e){ return delete0(root.right, e); } //返回值表示是否刪除成功 private boolean delete0(Node<E> x, E e){ if(x == null){//沒有找到待刪除的元素 return false; } if(cmp.compare(e, x.element) > 0){ boolean reval = delete0(x.right, e); if(reval == false){ return false; } int lh = getHight(x.left); int rh = getHight(x.right); if(lh - rh == 2){ if(getHight(x.left.left) > getHight(x.left.right)){ clockwistRotate(x); }else{ antiClockwiseRotate(x.left); clockwistRotate(x); } } }else if(cmp.compare(e, x.element) < 0){ boolean reval = delete0(x.left, e); if(reval == false){ return false; } int lh = getHight(x.left); int rh = getHight(x.right); if(rh - lh == 2){ if(getHight(x.right.right) > getHight(x.right.left)){ antiClockwiseRotate(x); }else{ clockwistRotate(x.right); antiClockwiseRotate(x); } } }else{//找到待刪除的元素 Node<E> P = x.parent; if(x.left == null){//左子支為空,可直接刪除,在這一層一定不需要旋轉 size--; if(P.left == x){ P.left = x.right; if(P.left != null){ P.left.parent = P; } }else{ P.right = x.right; if(P.right != null){ P.right.parent = P; } } }else if(x.right == null){//右子支為空,可直接刪除,在這一層一定不需要旋轉 size--; if(P.left == x){ P.left = x.left; if(P.left != null){ P.left.parent = P; } }else{ P.right = x.left; if(P.right != null){ P.right.parent = P; } } }else{//找到待刪除的節點,用后繼節點代替,然后刪除后繼節點 E nextVal = treeMin(x.right); x.element = nextVal; delete0(x.right, nextVal); int lh = getHight(x.left); int rh = getHight(x.right); if(lh - rh == 2){ if(getHight(x.left.left) > getHight(x.left.right)){ clockwistRotate(x); }else{ antiClockwiseRotate(x.left); clockwistRotate(x); } } } } x.h = Math.max(getHight(x.left), getHight(x.right)) + 1; return true; } public static void main(String[] args){ AVLtree<Integer> avl = new AVLtree<Integer>(); /*可自行添加插入,刪除操作進行測試*/ avl.insert(3); avl.insert(5); avl.insert(6); avl.insert(7); avl.insert(8); avl.insert(9); avl.preorderTraverse(); System.out.println(); System.out.println(avl.size()); avl.delete(7); avl.delete(8); avl.preorderTraverse(); System.out.println(); System.out.println(avl.size()); } }