平衡树之AVL树旋转

Posted Airsolstice

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了平衡树之AVL树旋转相关的知识,希望对你有一定的参考价值。

大一就学了数据结构,当听到AVL树的时候就很蒙,也没认真。最近开始认真看,那书上讲的何止是蒙,讲的我是莫名其妙。不知道为什么那么多人喜欢严蔚敏版的数据结构,没觉得好在哪里,讲的少,讲的粗略,讲的也是莫名其妙。可能是我的问题把,所以在网上搜了相关资料的,我一直认为,一个理论要马上接收,其实挺难的,我的做法是先不管那么多,掌握基本的操作就行,在你每次用的过程中,总会关心到某些值得推敲的地方,这样的抛砖引玉,显得理论没那么的生硬;因此,我写博客都是按照操作方法的标准写的,至于理论,百科多如牛毛,写了也不懂;后知后觉,似乎更加容易些。


仅是个人学习经验,有误请指教

这篇博客是我在网上看到的,他也是直接写操作的,并且写的挺明白的,所以我转了下

http://hxraid.iteye.com/blog/609949

平衡二叉树定义(AVL):

它或者是一颗空树,或者具有以下性质的二叉树:它的左子树和右子树的深度之差的绝对值不超过1,且它的左子树和右子树都是一颗平衡二叉树。


最小不平衡子树:指离插入节点最近且以平衡因子的绝对值大于1的节点作为根的子树。 

 

平衡因子(bf):结点的左子树的深度减去右子树的深度,那么显然-1<=bf<=1;

  很显然,平衡二叉树是在二叉排序树(BST)上引入的,就是为了解决二叉排序树的不平衡性导致时间复杂度大大下降,那么AVL就保持住了(BST)的最好时间复杂度O(logn),所以每次的插入和删除都要确保二叉树的平衡,那么怎么保持平衡呢?  

插入操作

       在平衡二叉树中插入结点与二叉查找树最大的不同在于要随时保证插入后整棵二叉树是平衡的。那么调整不平衡树的基本方法就是: 旋转,基本思路都是转换到左旋和右旋。

 

1) 右旋: 在最小平衡子树根节点平衡因子>=2且在根节点的左孩子的左孩子插入元素,进行右旋

       

 

2) 左旋: 在最小平衡子树根节点平衡因子>=-2且在根节点的右孩子的右孩子插入元素,进行左旋。

 

3) 右左:最小平衡子树根节点(80)的右孩子(100)的左孩子(90)的子节点(95)插入新元素,先绕根节点的右孩子节点(100)右旋,再围根节点(80)左旋

 

4) 左右:在最小平衡子树根节点(80)的左孩子(50)的右孩子(70)的子节点插入新元素,先绕根节点的左孩子节点(50)右旋,再围根节点(80)左旋

 

 

平衡二叉树性能分析


平衡二叉树的性能优势:

      很显然,平衡二叉树的优势在于不会出现普通二叉查找树的最差情况。其查找的时间复杂度为O(logN)。

 

平衡二叉树的缺陷:

      (1) 很遗憾的是,为了保证高度平衡,动态插入和删除的代价也随之增加


平衡二叉树的插入操作代码(平衡旋转)

Java代码  
  1. package net.hr.algorithm.search;  
  2. /**平衡因子枚举类*/  
  3. enum B  
  4. alanceFactor  
  5.     LH("左子树高"),EH("左右等高"),RH("右子树高");  
  6.       
  7.     private String illustration="";  
  8.       
  9.     private BalanceFactor(String s)  
  10.         this.illustration=s;  
  11.       
  12.       
  13.     public String toString()  
  14.         return this.illustration;  
  15.       
  16.   
  17. /** 
  18.  * 平衡二叉树结点 
  19.  */  
  20. class AVLNode<E extends Comparable<E>>  
  21.     /**结点关键字*/  
  22.     E key=null;  
  23.     /**结点的平衡因子*/  
  24.     BalanceFactor bFactor=BalanceFactor.EH;  
  25.     /**结点的直接父亲*/  
  26.     AVLNode<E> parent=null;  
  27.     /**结点的左右孩子*/  
  28.     AVLNode<E> lchild,rchild=null;  
  29.       
  30.     AVLNode(E k)  
  31.         this.key=k;  
  32.       
  33.     /** 
  34.      * 格式输出结点 
  35.      */  
  36.     public String toString()  
  37.         //String fomateStr="";  
  38.         //if(this.lchild==null)  
  39.         String lchildStr=(this.lchild==null)?"null":this.lchild.key.toString();  
  40.         String rchildStr=(this.rchild==null)?"null":this.rchild.key.toString();  
  41.         return this.key+"[lchild="+lchildStr+",rchild="+rchildStr+"]";  
  42.       
  43.   
  44.   
  45. /** 
  46.  * 平衡二叉查找树 
  47.  * @author heartraid 
  48.  */  
  49. public class AVL<E extends Comparable<E>>   
  50.   
  51.     /**树根*/  
  52.     private AVLNode<E> root=null;  
  53.     /**当前树是否变高*/  
  54.     public boolean isTaller=false;  
  55.       
  56.     public AVL()  
  57.       
  58.       
  59.       
  60.     public boolean insert(E key)  
  61.         System.out.print("插入["+key+"]:");  
  62.         if(key==nullreturn false;  
  63.         if(root==null)  
  64.             System.out.println("插入到树根。");  
  65.             root=new AVLNode<E>(key);  
  66.             return true;  
  67.           
  68.         else  
  69.             System.out.print("搜索路径[");  
  70.             return insertAVL(key,root);  
  71.           
  72.       
  73.       
  74.     private boolean insertAVL(E key,AVLNode<E> node)  
  75.         System.out.print(node.key+" —>");  
  76.         // 树中存在相同的key,不需要插入  
  77.         if(node.key.compareTo(key)==0)  
  78.             System.out.println("].  搜索有相同关键字,插入失败");  
  79.             isTaller=false;  
  80.             return false;  
  81.           
  82.         else  
  83.             //左子树搜索  
  84.             if(node.key.compareTo(key)>0)  
  85.                 //当前node的左孩子为空,则插入到结点的做孩子并修改结点的平衡因子为LH  
  86.                 if(node.lchild==null)  
  87.                     System.out.println("].  插入到"+node.key+"的左孩子");  
  88.                     AVLNode<E> newNode=new AVLNode<E>(key);  
  89.                     node.lchild=newNode; //设置左孩子结点  
  90.                     newNode.parent=node; //设置父亲结点  
  91.                     isTaller=true//树长高了  
  92.                   
  93.                 //左孩子不为空,则继续搜索下去  
  94.                 else  
  95.                     insertAVL(key,node.lchild);  
  96.                   
  97.                 //当前如果树长高了,说明是因为左孩子的添加改变了平衡因子(左高)。  
  98.                 if(isTaller)  
  99.                     System.out.print("          树变化了,"+node.key+"的平衡因子变化");  
  100.                     switch(node.bFactor)  
  101.                         //原来结点平衡因子是LH(bf=1),则左高以后bf=2,因此需要做左平衡旋转  
  102.                         case LH:   
  103.                             System.out.println("[LH=1 ——> LH=2]. 出现了不平衡现象[左比右高2]");  
  104.                             System.out.println("          ★ 以"+node.key+"为根将树进行左平衡处理");  
  105.                             leftBalance(node);  
  106.                             isTaller=false;   
  107.                             break;  
  108.                           
  109.                         //原来结点平衡因子是EH(bf=0),则左高了以后bf=1,不需要平衡处理。  
  110.                         case EH:  
  111.                             System.out.println("[EH=0 ——> LH=1]. 没有不平衡现象");  
  112.                             node.bFactor=BalanceFactor.LH;  
  113.                             isTaller=true;  
  114.                             break;  
  115.                           
  116.                         //原来结点平衡因子是RH(bf=-1),则左高以后bf=0,不需要平衡处理。  
  117.                         case RH:  
  118.                             System.out.println("[RH=-1 ——> EH=0]. 没有不平衡现象");  
  119.                             node.bFactor=BalanceFactor.EH;  
  120.                             isTaller=false;  
  121.                             break;  
  122.                           
  123.                     //end switch  
  124.                 //end if  
  125.             //end if  
  126.             //右子树搜索  
  127.             else  
  128.                 if(node.rchild==null)  
  129.                     System.out.println("].  插入到"+node.key+"的右孩子");  
  130.                     AVLNode<E> newNode=new AVLNode<E>(key);  
  131.                     node.rchild=newNode; //设置右孩子结点  
  132.                     newNode.parent=node; //设置父亲结点  
  133.                     isTaller=true//树长高了  
  134.                   
  135.                 else  
  136.                     insertAVL(key,node.rchild);  
  137.                   
  138.                 //当前如果树长高了,说明是因为右孩子的添加改变了平衡因子(右高)。  
  139.                 if(isTaller)  
  140.                     System.out.print("          树变化了,"+node.key+"的平衡因子变化");  
  141.                     switch(node.bFactor)  
  142.                         //原来结点平衡因子是LH(bf=1),则右高以后bf=0,不需要平衡处理。  
  143.                         case LH:   
  144.                             System.out.println("[LH=1 ——> EH=0]. 没有不平衡现象");  
  145.                             node.bFactor=BalanceFactor.EH;  
  146.                             isTaller=false;  
  147.                             break;  
  148. C++从入门到入土第二十一篇:二叉搜索树之AVL树

    C++从入门到入土第二十一篇:二叉搜索树之AVL树

    平衡树之AVL树旋转

    二叉平衡树之删除节点

    AVL树平衡旋转详解

    AVL树