美文网首页
AVL树及java实现

AVL树及java实现

作者: 检纠错能力 | 来源:发表于2017-12-25 15:39 被阅读0次

    二叉排序树查找、插入和删除操作的时间复杂度和树的深度n有关。构建树时,当先后插入的结点按关键字有序时,二叉排序树退化为链表,插入和删除的时间都会上升到O(n)。因此需要在构建二叉排序树的过程中进行“平衡化”处理,使之成为二叉平衡树。

    二叉平衡树,又称AVL树。它或者是一棵空树,或者是具有下列性质的树:

    1)具备二叉排序树的所有性质;

    2)左子树和右子树深度差的绝对值不超过1;

    3)左子树和右子树都是二叉平衡树

    以上,得出AVL树的查找、插入和删除在平均和最坏情况下都是O(logn)。

    对于旋转定义可以参考链接:www.cnblogs.com/skywang12345/p/3576969.html#a1以及www.cnblogs.com/Camilo/p/3917041.html

    /**
     * node节点
     * @author SUJiannan
     */
    class AVLNode {
        // 单node 高度为0 ; 
        // 空树 高度为 -1
        public int value; //值;为简化操作
        public AVLNode left;  //左孩子结点  
        public AVLNode right; //右孩子结点  
        public int height;    //树的高度  
        public AVLNode(int value) {
            this.value = value;
            this.height = 0;  // 树的init高度为0
        }
        public AVLNode() {
        }
    }
    
    package tree;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 二叉平衡树 
     * @author SUJiannan
     * @see 下午8:26:31
     * 图例参考:http://www.cnblogs.com/Camilo/p/3917041.html
     */
    public class AVLTree {
    
        private AVLNode root;    // 根结点
        /**
         * 计算树的高度  
         */
        public int height(AVLNode node){  
            return node == null ? -1 : node.height;  // 空树高度为-1
        } 
        
        /**
         * 四种旋转实现(LL,LR,RL,RR) 
         */
        // 单右旋 LL  返回值:旋转后的根节点
        // 当根结点左子树的左子树中的节点导致根结点的平衡因子为2时,采用LL型旋转进行调整。
        private AVLNode llRotate(AVLNode node){
            AVLNode x = node.left;
            node.left = x.right;
            x.right = node;
            
            node.height = Math.max(this.height(node.right),this.height(node.left)) + 1;
            x.height = Math.max(this.height(x.left), node.height) + 1;
            return x;  
        }
        
        // 单左旋 RR
        // 根结点右子树的右子树中的节点导致根结点的平衡因子为-2时,采用RR型旋转进行调整。
        private AVLNode rrRotate(AVLNode node){
            AVLNode x = node.right;
            node.right = x.left;
            x.left = node;
            
            node.height = Math.max(this.height(node.right),this.height(node.left)) + 1;
            x.height = Math.max(this.height(x.right), node.height) + 1;
            return x;  
        }
        
        //  LR型(先单次左旋,再单次右旋)
        // 当根结点左子树的右子树中的节点导致根结点的平衡因子为2时,采用LR型旋转进行调整。
        private AVLNode lrRotate(AVLNode node){
            node.left = rrRotate(node.left); // 左子树部分左旋
            return llRotate(node); // 整体右旋ll
        }
        
        // RL型(先单次右旋,再单次左旋)
        // 当根结点右子树的左子树中的节点导致根结点的平衡因子为-2时,采用RL型旋转进行调整。
        private AVLNode rlRotate(AVLNode node){
            node.right = llRotate(node.right); //  右子树部分右旋
            return rrRotate(node);
        }
        
        /**
         * 插入操作
         */
        public void insert(int val) {
            this.root = insert(root,val);
        }
        
        public AVLNode insert(AVLNode node, int val){
            if(node == null) {
                return new AVLNode(val);
            }
            int cmp = node.value - val;
            if(cmp > 0) {
                node.left = insert(node.left,val);
                if(height(node.left) - height(node.right) == 2) {
                    if(node.left.value > val) {
                        // ll 
                        node = llRotate(node);
                    } else {
                        // lr
                        node = lrRotate(node);
                    }
                }
            } else if(cmp < 0) {
                node.right = insert( node.right,val);
                if(height(node.left) - height(node.right) == -2) {
                    if(val > node.right.value) {
                        // rr
                        node = rrRotate(node);
                    } else {
                        //rl
                        node = rlRotate(node);
                    }
                }
            } else {
                // 相等 无操作 
                return null;
            }
            // 插入后 树的高度  
            node.height = Math.max(height(node.left), height(node.right)) + 1; 
            return node; 
        }
        
        /**
            * 删除结点(z),返回根节点
            * 参数说明:
            *   val:待删除的结点
            * return:
            *     根节点
         */
        public AVLNode remove(int val) {
            AVLNode root = remove(this.root , val);
            return root;
        }
    
        private AVLNode remove(AVLNode node, int val) {
            if(node == null) {
    //          System.out.println("not find");
                return null;
            } 
            // find value
            int cmp = node.value - val;
            if(cmp > 0) {
                node.left = remove(node.left,val);
                if(this.height(node.left) - height(node.right) == -2)  {
                    AVLNode tmpNode = node.right;
                    if(height(tmpNode.left) > height(tmpNode.right)) {
                        //rl
                        node = this.rlRotate(node);
                    } else {
                        //rr
                        node = this.rrRotate(node);
                    }
                }
            } else if (cmp < 0) {
                node.right = remove(node.right,val);
                if ( height(node.left ) - height(node.right) == 2) {
                    AVLNode tmpNode = node.left;
                    if(height(tmpNode.left) < height(tmpNode.right)) {
                        // lr
                        node = lrRotate(node);
                    } else {
                        // ll
                        node = llRotate(node);
                    }
                }
            } else {
                // find it and delete it
                if(node.left == null && node.right == null) {
                    node = null;
                } else if(node.left != null && node.right == null ) {
                    node = node.left;
                    
                    // delete后 树的高度  
                    node.height = Math.max(height(node.left), height(node.right)) + 1; 
                    
                } else if(node.left == null && node.right != null) {
                    node = node.right;
                    
                    // delete后 树的高度  
                    node.height = Math.max(height(node.left), height(node.right)) + 1; 
                    
                } else {
                    // 获取左子树最大的node
                    AVLNode x = node.left;
                    while(x.right != null) {
                        x = x.right;
                    }
                    // 将该最大节点的值赋值给tree
                    node.value = x.value;
                    // 删除该最大节点 
                    node.left = remove(node.left , x.value);
                    
                    // delete后 树的高度  
                    node.height = Math.max(height(node.left), height(node.right)) + 1; 
                }
            }
            return node;
        }
    
        /**
         * 查找当前value对应的node
         */
        public AVLNode get(int value) {
            AVLNode avlNode = get(value,this.root);
            // 利用int最小值代表未找到
            return avlNode == null ? new AVLNode(Integer.MIN_VALUE) : avlNode;
        }
        private AVLNode get(int value,AVLNode node) {
            if(node == null) {
                return null; // not find
            }
            int cmp = value - node.value;
            if(cmp > 0) {
                return get(value , node.right);
            } else if(cmp < 0) {
                return get(value , node.left);
            } else {
                // find it
                return node;
            }
        }
        
        
        
        /**
         *  中序遍历
         */
        public void printZhong(){
            List list = new ArrayList();
            printZ(this.root , list);
            System.out.println("中序遍历:" + list);
        }
        private void printZ(AVLNode node, List list) {
            if(node != null) {
                printZ(node.left ,list) ;
                list.add(node.value);
                printZ(node.right ,list) ;
            }
        }
        
        /**
         *  先序遍历
         */
        public void printXian(){
            List list = new ArrayList();
            printX(this.root , list);
            System.out.println("先序遍历:" + list);
        }
        private void printX(AVLNode node, List list) {
            if(node != null) {
                list.add(node.value);
                printX(node.left ,list) ;
                printX(node.right ,list) ;
            }
        }
    }
    

    测试代码:

    public static void main(String[] args) {
            int arr[]= {3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9};
            AVLTree a = new AVLTree();
            for (int i : arr) {
                a.insert(i);
            }
            a.remove(5);
            a.remove(6);
            a.printXian();
            a.printZhong();
            
            AVLNode avlNode = a.get(900);
            System.out.println("寻找9的node节点:" + avlNode.value);
    }
    

    运行结果:
    先序遍历:[7, 2, 1, 4, 3, 13, 11, 9, 8, 10, 12, 15, 14, 16]
    中序遍历:[1, 2, 3, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

    相关文章

      网友评论

          本文标题:AVL树及java实现

          本文链接:https://www.haomeiwen.com/subject/kevlgxtx.html