加入收藏 | 设为首页 | 会员中心 | 我要投稿 衡阳站长网 (https://www.0734zz.cn/)- 数据集成、设备管理、备份、数据加密、智能搜索!
当前位置: 首页 > 服务器 > 安全 > 正文

自己动手实现java数据结构(七) AVL树

发布时间:2021-04-01 19:18:56 所属栏目:安全 来源:网络整理
导读:1.AVL树介绍 前面我们已经介绍了二叉搜索树。普通的二叉搜索树在插入、删除数据时可能使得全树的数据分布不平衡,退化,导致二叉搜索树最关键的查询效率急剧降低。这也引出了平衡二叉搜索树的概念,平衡二叉搜索树在此前的基础上,通过一系列的等价变换使二

  AVL树的实现继承自前面介绍的普通二叉搜索树—TreeMap类。由于AVL树通过树高作为判断平衡的依据,因此在二叉搜索树TreeMap的节点中增加了一个height(高度)属性。

/**
     * 二叉搜索树 内部节点
     * */
    static class EntryNode<K,V> implements Map.EntryNode<K,V>{
        
         * key值
         * */
        K key;

        
         * value值
         * 
        V value;

        
         * 高度值
         * */
        int height;

        
         * 左孩子节点
         * 
        EntryNode<K,1)"> left;

        
         * 右孩子节点
         *  right;

        
         * 双亲节点
         *  parent;

        EntryNode(K key,V value) {
            this.key = key;
            this.value = value;
            this.height = 1;
        }

        EntryNode(K key,V value,EntryNode<K,1)"> parent) {
            this.parent = parent;
            ;
        }

        @Override
        public K getKey() {
            return key;
        }

        @Override
         V getValue() {
             value;
        }

        @Override
        public void setValue(V value) {
             String toString() {
            return key + "=" + value + " height=" + height;
        }
    }

3.2 辅助方法

  在AVL树的实现过程中,存在一些通用的,细节的逻辑,将其抽取成辅助函数,简化主要代码逻辑,增强代码可读性和可维护性。

   
     * 当前节点 是否满足AVL树约定的平衡条件
     * private boolean isAVLBalanced(EntryNode<K,1)"> entryNode){
        //获得 左子树高度
        int leftChildHeight = getHeight(entryNode.left);
        获得右子树高度
        int rightChildHeight = getHeight(entryNode.right);

        获得左右子树高度差
        int difference = leftChildHeight - rightChildHeight;

        高度差绝对值在1之内,认为是满足AVL平衡条件
        return -1 <= difference && difference <= 1;
    }

    
     * 更新当前节点高度
     * void updateHeight(EntryNode<K,1)">int leftHeight =int rightHeight =左右子树高度较高者 + 1
        entryNode.height = 1 + Math.max(leftHeight,rightHeight);
    }

    
     * 获得当前节点的高度
     * int getHeight(EntryNode<K,1)">if(entryNode == null){
            return 0;
        }else{
             entryNode.height;
        }
    }
    
    
     * 获得较高子树分支孩子节点
     private EntryNode<K,V> getTallerChild(EntryNode<K,1)">if(leftChildHeight > rightChildHeight){
            左子树高度 > 右子树高度
             entryNode.left;
        }左子树高度 <= 右子树高度
             entryNode.right;
        }
    }

    
     * 是否是左孩子
     * boolean isLeftChild(EntryNode<K,V> parent,EntryNode<K,1)"> target){
        return getRelativeByParent(parent,target) == RelativePosition.LEFT;
    }

3.3 3+4重构实现

  refactor34方法:方法的参数为3+4重构目标拓扑结构所需的三个节点(左,中,右),左右孩子的分别挂载的四颗子树。在refactor34方法中,依照3+4重构的原理直接调整节点和子树的关系引用,拼接成最终的所需的结果。

  rotateAt方法:方法的参数为重平衡所涉及到的祖孙三代节点(Node、Son、GrandSon),通过判断N、S、GS的拓扑结构,决定调用refactor34方法时传递的参数。方法的返回值为3+4重构后的子树树根节点,便于重平衡操作之后,将重构后新的子树重新接入整颗AVL树中。

   
     * 3+4 重构
     *  refactor34(
        EntryNode<K,V> leftNode,V> middleNode,1)"> rightNode,V> llChild,1)"> lrChild,V> rlChild,1)"> rrChild){

        调整 左节点和对应子树的拓扑结构
        leftNode.left = llChild;
        if(llChild != ){
            llChild.parent = leftNode;
        }

        leftNode.right = lrChild;
        if(lrChild != ){
            lrChild.parent = leftNode;
        }
        更新高度
        updateHeight(leftNode);

        调整 右节点和对应子树的拓扑结构
        rightNode.left = rlChild;
        if(rlChild != ){
            rlChild.parent = rightNode;
        }

        rightNode.right = rrChild;
        if(rrChild != ){
            rrChild.parent = rightNode;
        }
                updateHeight(rightNode);

        调整 中间节点 和左、右节点的拓扑结构
        middleNode.left = leftNode;
        middleNode.right = rightNode;

        leftNode.parent = middleNode;
        rightNode.parent = middleNode;
                updateHeight(middleNode);
    }

    
     * 进行旋转,使用3+4重构完成重平衡
     * @return 重构之后子树的树根节点
     *  grandSonNode){
        if(isLeftChild(currentNode,sonNode)){
            左 zig
            (isLeftChild(sonNode,grandSonNode)){
                左-左   zig-zig旋转
                refactor34(grandSonNode,sonNode,currentNode,grandSonNode.left,grandSonNode.right,sonNode.right,currentNode.right);

                 sonNode;
            }{
                左-右   zig-zag旋转
                refactor34(sonNode,grandSonNode,sonNode.left,1)"> grandSonNode;
            }
        }右 zag
            右-左   zag-zig旋转
                refactor34(currentNode,currentNode.left,sonNode.right);

                 grandSonNode;
            }右-右   zag-zag旋转
 sonNode;
            }
        }
    }

3.4 插入方法重写

  AVL树的实现中,重写了普通二叉搜索树的插入方法(put),整体逻辑和之前TreeMap的实现大致一样,唯一的区别在于,当插入了新的节点之后,会调用afterNewNodeInsert方法,进行AVL树重平衡的一系列操作。

  afterNewNodeInsert方法:

  参数为新插入的节点。从下至上,遍历检查新插入节点的历代祖先,判断其是否失衡。一旦发现当前迭代的祖先节点失衡,则调用rotateAt方法,使其恢复平衡,全树重新接入子树;

(编辑:衡阳站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读