算法7:AVL树实现

二叉排序树(BST, Binary Sort Tree)也称二叉查找树(Binary Search Tree), 或二叉搜索树。

定义:一颗二叉树,满足以下属性:

  • 左子树的所有的值小于根节点的值
  • 右子树的所有值大于根节点的值
  • 左、右子树满足以上两点

    那么我们如何去构建一个自己的二叉排序树呢?算法实现思路如下:

  二叉排序树只是对值进行了排序,但是如果我们对二叉排序树进行树的平衡操作,即对树进行旋转,那么就引出了本文的重要知识点,平衡二叉树(AVL Tree)。《大话数据结构》是这样解释的:

 

 下面通过几张图片来对AVL树有一个基本的认识:

为什么图2,图3不是平衡二叉树呢?

平衡二叉树首先是一颗二叉排序树,因为图2节点值58,它的左节点值为59,不满足二叉排序树的条件,因此更不可能是平衡二叉树了。

图3中,节点58的右子树为空,而左子树的高度为2,不满足左右节点高度差至多为1的条件,因此也不是平衡二叉树

下面通过过右旋,左右旋来做一个简单的介绍。(左旋和右旋相反,左右旋和右左旋相反)

右旋:即对树的根节点重新判定,即左子树最下层的左节点新增节点值,那么可以通过将新生成的根节点往右拉,即可实现平衡。即将新的根节点40拉到旧的根节点50的位置。

 左右旋:如下图中所展示,先对左子树进行左旋,将原来左子树根节点20变为30,即将30往左拉; 然后再进行右旋,即将整颗树的新的根节点30往右拉

 下面通过一张图片,总结一下分别在什么情况下需要左旋,左右旋,右旋,右左旋。 

左旋,右旋只需要一次旋转即可完成树的平衡

左右旋,右左旋需要2次旋转才能完成树的平衡

 

下面直接接上代码,实现AVL Tree的构造

package unit2.class35;

/**
 * 按照key进行存储的AVL树,
 * key是排序的依据,key不可变
 */
public class AVLTree<K extends Comparable, V>
{
    AVLNode<K, V> root; //根节点
    int size = 0;           //节点数量

    public AVLTree(){
        root = null;
        int size = 0;
    }

    //Node节点数据结构
    public static class AVLNode<K extends Comparable,V>
    {
        public AVLNode<K, V> left;
        public AVLNode<K, V> right;
        public K k;
        public V v;
        int height;

        AVLNode(K key, V value){
            k = key;
            v = value;
            height = 1;
        }
    }

    private void setHeight(AVLNode<K, V> cur){
        cur.height = Math.max(cur.left != null ? cur.left.height : 0,
                cur.right != null ? cur.right.height : 0) + 1;
    }

    //右旋
    private AVLNode<K, V> rightRotate (AVLNode<K, V> cur)
    {
        AVLNode<K, V> left = cur.left;
        cur.left = left.right;
        left.right = cur;

        //先子后父,顺序不能颠倒
        setHeight(cur);
        setHeight(left);

        return left;
    }

    //左旋
    private AVLNode<K, V> leftRotate (AVLNode<K, V> cur)
    {
        AVLNode<K, V> right = cur.right;
        cur.right = right.left;
        right.left = cur;

        //先子后父,顺序不能颠倒
        setHeight(cur);
        setHeight(right);

        return right;
    }


    //旋转
    private  AVLNode<K, V> rotate (AVLNode<K, V> cur)
    {
        if (cur == null) {
            return null;
        }
         int leftHeight = cur.left != null ? cur.left.height : 0;  //左子树高度
         int rightHeight = cur.right != null ? cur.right.height : 0;   //右子树高度

         //左、右子树高度差超过1,说明失衡,需要旋转
         if (Math.abs(leftHeight - rightHeight) > 1)
         {
             if (leftHeight > rightHeight) {
                 int leftLeftHeight = cur.left != null && cur.left.left != null ? cur.left.left.height : 0;
                 int leftRightHeight = cur.left != null && cur.left.right != null ? cur.left.right.height : 0;

                  if (leftLeftHeight > leftRightHeight) { //右旋
                      cur = rightRotate(cur);
                  }
                  else { //左右旋
                      cur.left = leftRotate(cur.left);
                      cur = rightRotate(cur);
                  }
             }
             else {
                 int rightLeftHeight = cur.right != null && cur.right.left != null ? cur.right.left.height : 0;
                 int rightRightHeight = cur.right != null && cur.right.right != null ? cur.right.right.height : 0;

                 if (rightRightHeight > rightLeftHeight) { //左旋
                     cur = leftRotate(cur);
                 }
                 else { //右左旋
                     cur.right = rightRotate(cur.right);
                     cur = leftRotate(cur);
                 }
             }
         }
        //每个节点已经在旋转的时候重置了height
        //所以此处无需再次设置height
        return cur;
    }

    private AVLNode<K, V> findExistOrPreNode (K key)
    {
        AVLNode<K, V> cur = root;
        AVLNode<K, V> pre = root;

        while (cur != null) {
            pre = cur;

            if (key.compareTo(cur.k) == 0) { //找到当前节点
                break;
            }
            else if (key.compareTo(cur.k) > 0) {
                cur = cur.right;
            }
            else {
                cur = cur.left;
            }
        }

        // pre的key,要么等于当前key, 要么是null或者最近接key的一个节点
        return pre;
    }

    private AVLNode<K, V> add(AVLNode<K, V> cur, K key, V value)
    {
        if (cur == null) {
            return new AVLNode(key, value);
        }

        if (key.compareTo(cur.k) > 0) {
            cur.right = add(cur.right, key, value);
        }
        else { //不存在相等的情况,findExistOrPreNode之前已经检查过了
            cur.left =  add(cur.left, key, value);
        }

        //新增了节点,当前高度需要调整。
        //旋转的时候,需要节点的高度判断
        setHeight(cur);
        //旋转
        return rotate(cur);
    }

    //无需对cur做非空判断,因为remove已经检查key是否存在
    private AVLNode<K, V> delete(AVLNode<K, V> cur, K key)
    {
        if (key.compareTo(cur.k) > 0) {
            cur.right = delete(cur.right, key);
        }
        else if (key.compareTo(cur.k) < 0) { //不存在相等的情况,findExistOrPreNode之前已经检查过了
            cur.left =  delete(cur.left, key);
        }
        else {
            if (cur.left == null && cur.right == null) {
                cur = null;
            }
            else if (cur.left != null && cur.right == null){
                cur = cur.left;
            }
            else if (cur.left == null && cur.right != null){
                cur = cur.right;
            }
            else {
                AVLNode<K, V> des = cur.right;
                while (des.left != null) {
                    des = des.left;
                }

                //必须走递归,才能确保删除后,由下往上每一层节点旋转正确
                //如果是SB树,删除不需要旋转保持平衡,那么此处直接删除即可,无需递归
                cur.right = delete(cur.right, des.k);

                des.left = cur.left;
                des.right = cur.right;
                cur = des;
            }
        }
        if (cur != null) {
            setHeight(cur);
        }
        return rotate(cur);
    }

    //查询是否存在
    public boolean containsKey (K key)
    {
        AVLNode<K, V> findNode = findExistOrPreNode(key);
        return findNode != null && key.compareTo(findNode.k) == 0;
    }

    //查询树的节点数
    public int size(){
        return size;
    }

    //查询树的高度
    public int height() {
        return root != null ? root.height : 0;
    }

    public V get(K key)
    {
        if (key == null) {
            //return;
            throw new IllegalArgumentException("key can not be null");
        }
        AVLNode<K, V> findNode = findExistOrPreNode(key);
        return findNode != null ? findNode.v : null;
    }

    public K floorKey(K key) {
        if (key == null) {
            return null;
        }
        AVLNode<K, V> lastNoBigNode = findExistOrPreNode(key);
        return lastNoBigNode == null ? null : lastNoBigNode.k;
    }

    public K ceilingKey(K key) {
        if (key == null) {
            return null;
        }
        AVLNode<K, V> lastNoSmallNode = findLastNoSmallIndex(key);
        return lastNoSmallNode == null ? null : lastNoSmallNode.k;
    }

    public K firstKey() {
        if (root == null) {
            return null;
        }
        AVLNode<K, V> cur = root;
        while (cur.left != null) {
            cur = cur.left;
        }
        return cur.k;
    }

    public K lastKey() {
        if (root == null) {
            return null;
        }
        AVLNode<K, V> cur = root;
        while (cur.right != null) {
            cur = cur.right;
        }
        return cur.k;
    }

    private AVLNode<K, V> findLastNoBigIndex(K key) {
        AVLNode<K, V> ans = null;
        AVLNode<K, V> cur = root;
        while (cur != null) {
            if (key.compareTo(cur.k) == 0) {
                ans = cur;
                break;
            } else if (key.compareTo(cur.k) < 0) {
                cur = cur.left;
            } else {
                ans = cur;
                cur = cur.right;
            }
        }
        return ans;
    }

    private AVLNode<K, V> findLastNoSmallIndex(K key) {
        AVLNode<K, V> ans = null;
        AVLNode<K, V> cur = root;
        while (cur != null) {
            if (key.compareTo(cur.k) == 0) {
                ans = cur;
                break;
            } else if (key.compareTo(cur.k) < 0) {
                ans = cur;
                cur = cur.left;
            } else {
                cur = cur.right;
            }
        }
        return ans;
    }
    //新增、修改
    public void put (K key, V value)
    {
        if (key == null) {
            //return;
            throw new IllegalArgumentException("key can not be null");
        }

        //寻找当前key
        AVLNode<K, V> findNode = findExistOrPreNode(key);

        /**
         * 如果当前key存在,说明是修改可以的value
         * 如果当前key不存在,那么是null或者最近接key的一个节点
         *
         * key是排序的依据,key值不可变。
         * 如果是简单类型的数据,比如int类型的值构造的AVL树,那么不应当提供修改功能
         */
        if (findNode != null && key.compareTo(findNode.k) == 0) {
            findNode.v = value;
        }
        else {
            size++;
            root = add(root, key, value);
        }
    }

    //删除
    public void remove(K key)
    {
        if (key == null) {
            throw new IllegalArgumentException("key can not be null");
        }

        if (containsKey(key)) {
            size--;
            root = delete(root, key);
        }
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值