数据结构: AVL树

来源:互联网 发布:爱果园团购 淘宝 编辑:程序博客网 时间:2024/06/06 00:25

二叉查找树的主要缺点:
很多时候输入得序列都是有序或基本有序的,二叉查找树(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();    }}
0 0
原创粉丝点击