数据结构: AVL树

二叉查找树的主要缺点:
很多时候输入得序列都是有序或基本有序的,二叉查找树(BST)在最坏的情况下会退化成链表。树的高度会变成N, 而BST的性能又依赖于树的高度。插入、删除、查找等操作的时间复杂度都变成了O(N)。所以我们需要通过一定的方式来降低树的高度

AVL树是一种自平衡二叉查找树,AVL树要求它的每个节点的左右子树的高度差不超过1. 它保证了树的深度是O(logN), 所以它不会出现上述BST的缺点。 不管输入序列是什么样的,都能保持良好的性能。树的高度都为O(logN)

AVL树的缺点是频繁的旋转、需要维护树的节点的平衡以及总体的复杂性,尤其是删除操作。这些缺点使得AVL树没有成为实现字典的标准结构。

AVL树解决了BST在最坏情况下效率低下的问题。换句话说,BST不能保证查询和插入操作花费log时间,而AVL树提供了这种保证。

具体的原理就不再重复了,书上和网上有非常详细的解释。
这里仅提供我自己实现AVL树的代码和注释。

package trees;

/** * AVL树,重构~ * @author earayu * @param <K> * @param <V> */
public class AVL <K extends Comparable<? super K>, V> {

    private class AVLNode{
        K key;
        V val;
        int height;
        AVLNode leftChild;
        AVLNode rightChild;

        AVLNode(K key, V val, AVLNode leftChild, AVLNode rightChild){
            this.key = key;
            this.val = val;
            this.height = 0;//height为该节点到叶子节点的最大距离
            this.leftChild = leftChild;
            this.rightChild = rightChild;
        }
    }

    private AVLNode root;

    public AVL(){
        root = null;
    }

    /** * 返回AVL树是否为空 * @return */
    public boolean isEmpty(){
        return root == null;
    }

    /** * 用键值对创建一个节点插入AVL树,将自动平衡 * @param key * @param val */
    public void insert(K key, V val){
        root = insert(root, key, val);
    }

    /** * 删除键为key的元素 * @param key */
    public void remove(K key){
        root = remove(root, key);
    }

    /** * 先序遍历AVL树 */
    public void prePrint(){
        prePrint(root);
    }

    /**************************************************************************************************/

    /** * 返回该节点的高度,空节点返回-1. * @param t * @return */
    private int height(AVLNode t){
        return t == null ? -1 : t.height;
    }

    /** * 将key,val插入树t中,然后返回树t。除了最后要平衡一下,代码跟BST完全相同。 * @param t * @param key * @param val * @return */
    private AVLNode insert(AVLNode t, K key, V val){
        if(t == null)
            return new AVLNode(key, val, null, null);
        int cmp = key.compareTo(t.key);
        if(cmp < 0)
            t.leftChild = insert(t.leftChild,key,val);
        else if(cmp > 0)
            t.rightChild = insert(t.rightChild,key,val);
        else
            t.val = val;

        return balance(t);
    }

    /** * AVL树的四种旋转,这里只提供代码。 * @param t * @return */
    private AVLNode balance( AVLNode t )
    {
        if( t == null )
            return t;

        if( height( t.leftChild ) - height( t.rightChild ) > 1 )
            if( height( t.leftChild.leftChild ) >= height( t.leftChild.rightChild ) )
                t = rotateLL( t );
            else
                t = rotateLR( t );
        else
        if( height( t.rightChild ) - height( t.leftChild ) > 1 )
            if( height( t.rightChild.rightChild ) >= height( t.rightChild.leftChild ) )
                t = rotateRR( t );
            else
                t = rotateRL( t );

        t.height = Math.max( height( t.leftChild ), height( t.rightChild ) ) + 1;
        return t;
    }

    /** * 删除t中键为key的元素,返回t。除了balance,跟BST的代码也几乎相同 * @param t * @param key * @return */
    private AVLNode remove(AVLNode t, K key){
        if(t == null)
            return t;
        int cmp = key.compareTo(t.key);
        if( cmp < 0 )
            t.leftChild = remove(t.leftChild, key);
        else if( cmp > 0 )
            t.rightChild = remove(t.rightChild, key );
        else
            if(t.leftChild == null || t.rightChild == null)
                t = t.leftChild==null?t.rightChild:t.leftChild;
            else{
                AVLNode minNode = findMin(t.rightChild);
                t.key = minNode.key;
                t.val = minNode.val;
                t.rightChild = remove(t.rightChild, minNode.key);
            }

        return balance(t);
    }

    /** * 返回AVL树t中的键最小的节点 * @param t * @return */
    private AVLNode findMin(AVLNode t) {
        if (t == null) {
            return null;
        }
        while (t.leftChild != null) {
            t = t.leftChild;
        }
        return t;
    }

    private AVLNode rotateLL(AVLNode k1){
        AVLNode k2 = k1.leftChild;
        k1.leftChild = k2.rightChild;
        k2.rightChild = k1;
        k1.height = Math.max(height(k1.leftChild), height(k1.rightChild) ) + 1;
        k2.height = Math.max(height(k2.leftChild), k1.height) + 1;
        return k2;
    }

    private AVLNode rotateRR(AVLNode k1){
        AVLNode k2 = k1.rightChild;
        k1.rightChild = k2.leftChild;
        k2.leftChild = k1;
        k1.height = Math.max(height(k1.leftChild), height(k1.rightChild)) + 1;
        k2.height = Math.max(k1.height, height(k2.rightChild)) + 1;
        return k2;
    }

    private AVLNode rotateLR(AVLNode k1){
        AVLNode k2 = k1.leftChild;
        k1.leftChild = rotateRR(k2);
        return rotateLL(k1);
    }

    private AVLNode rotateRL(AVLNode k1){
        AVLNode k2 = k1.rightChild;
        k1.rightChild = rotateLL(k2);
        return rotateRR(k1);
    }

    private void prePrint(AVLNode t){
        if(t != null){
            System.out.println(t.val +": " + t.height );
            prePrint(t.leftChild);
            prePrint(t.rightChild);
        }
    }

    public static void main(String[] args) {
        AVL<Integer,Integer> a = new AVL<>();
        //for(int i=0;i<11;i++)
        // a.insert(i, i);
        a.insert(4, 4);
        a.insert(1, 1);
        a.insert(5, 5);
        a.insert(0, 0);
        a.insert(3, 3);
        a.insert(2, 2);

        a.remove(4);
        a.remove(5);

        a.prePrint();

    }

}

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