经典查找算法 -AVL树

1,介绍—->来自百度

平衡二叉树(Balanced Binary Tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树AVL替罪羊树Treap伸展树等。 最小二叉平衡树的节点的公式如下 F(n)=F(n-1)+F(n-2)+1 这个类似于一个递归的数列,可以参考Fibonacci(斐波那契)数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量。

      2,AVL的旋转             

AVL树的基本操作一般涉及运做同在不平衡的二叉查找树所运做的同样的算法。但是要进行预先或随后做一次或多次所谓的”AVL旋转”。

      假设由于在二叉排序树上插入结点而失去平衡的最小子树根结点的指针为a(即a是离插入点最近,且平衡因子绝对值超过1的祖先结点),则失去平衡后进行进行的规律可归纳为下列四种情况:

AVL在插入和删除节点造成不平衡的时候需要对发生不平衡的节点及时调整,调整方法为旋转操作。根据造成不平衡的节点出构型可分为:LL 、RR 、LR 、RL型,对应的操作则为单旋和双旋,

下图所示为LL构型,在B节点的左子树上插入节点导致A节点失衡,调整过程为:以B节点为轴心,A节点顺时针旋转至B的右子树,A的右子树又B的右子树代替。通过右旋操作,返回以B为Root的平衡子树。 RR够型和LL够型成对称关系,操作方向相反,此处就省略了。

       2.1 LL型

《经典查找算法 -AVL树》

       2.2 RR型

《经典查找算法 -AVL树》

下图所示为LR构型,在B节点的右子树上插入新节点导致A节点失衡,调整过程分两个步骤:首先以C为轴心,B绕C逆时针旋转,生成的子树作为A的左子树;这样就变化成了LL型,然后用上图所示的方法调整即可。通过先左旋后右旋,返回以C为Root的平衡子树。RL型和LR型呈对称状,此处也省略。

       2.3 LR型

《经典查找算法 -AVL树》

       2.4 RL型

          RL型和上面的LR刚好相反

          源码片段:

                            节点定如下:这是内部类

 static class Entry<E>
    {  
        E element;  
        Entry<E> parent;  
        Entry<E> left;  
        Entry<E> right;  
        int balance = EH;   //平衡因子,只能为1或0或-1  
          
        public Entry(E element,Entry<E> parent)
        {  
            this.element = element;  
            this.parent = parent;  
        }  
          
        private Entry(){}  
  
        @Override  
        public String toString() {  
            return element+" BF="+balance;  
        }  
              
    }  

基本定义

   private static final int LH = 1;    //左高  
    private static final int EH = 0;    //等高  
    private static final int RH = -1;   //右高  

左旋

 private void rotateLeft(Entry<E> p)
    {  
        System.out.println("绕"+p.element+"左旋");  
        if(p!=null){  
            Entry<E> r = p.right;  
            p.right = r.left;   //把p右子树的左节点嫁接到p的右节点,如上图,把BL作为A的右子节点  
            if (r.left != null) 
            {//如果B的左节点BL不为空,把BL的父节点设为A  
                r.left.parent = p;  
            }
            r.parent = p.parent;  //A的父节点设为B的父节点  
            if (p.parent == null)         //如果p是根节点  
            {
                root = r;                 //r变为父节点,即B为父节点
            }
            else if (p.parent.left == p)  //如果p是左子节点
            {
                p.parent.left = r;        //p的父节点的左子树为r
            }
            else
            {                          //如果p是右子节点  
                p.parent.right = r;       //p的父节点的右子树为r
            }
            r.left = p;                   //p变为r的左子树,即A为B的左子树  
            p.parent = r;                 //同时更改p的父节点为r,即A的父节点为B  
        }  
    }  

右旋

  private void rotateRight(Entry<E> p)
    {  
        System.out.println("绕"+p.element+"右旋");  
        if(p!=null){  
            Entry<E> l = p.left;    
            p.left = l.right;    //把B的右节点BR作为A的左节点  
            if (l.right != null)   //如果BR不为null,设置BR的父节点为A
            {
                l.right.parent = p;
            }
            l.parent = p.parent;  //A的父节点赋给B的父节点  
            if (p.parent == null)   //如果p是根节点
            {
                root = l;          //B为根节点
            }
            else if (p.parent.right == p) //如果A是其父节点的左子节点
            {
                p.parent.right = l;     //B为A的父节点的左子树
            }
            else                        //如果A是其父节点的右子节点  
            {   p.parent.left = l;      //B为A的父节点的右子树
            }
            l.right = p;                //A为B的右子树  
            p.parent = l;               //设置A的父节点为B
            
        }  
    }  

源代码下载

    原文作者:查找算法
    原文地址: https://blog.csdn.net/sjyttkl/article/details/70187316
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞