36:AVL树

package algorithmbasic.basicsets.class36;

import java.util.Map;

public class AVL {
    //AVL树 -- 平衡的搜索二叉树 -- 对树的平衡有极高的要求

    //注意:是必须可以比较的 -- 根据key的大小来判断到底是放在节点的左侧还是右侧 --
    //从而出现了大小位置的放置 -- 从而实现搜索的功能 -- 从而实现区间范围的查询
    public static class AvlNode<K extends Comparable<K>, V> {
        public K key;
        public V value;
        public AvlNode l;
        public AvlNode r;
        //平衡因子 -- 以当前节点为头节点的树的高度
        public Integer h;

        public AvlNode(K key, V value) {
            this.key = key;
            this.value = value;
            this.h = 0;
        }
    }

    public static class AvlTreeMap<K extends Comparable<K>, V> {
        AvlNode<K, V> root;

        //注意:1:搜索二叉树不接受重复的key 2:之所以有返回值是因为有可能换头
        //思路:采用递归的方法 --> 递:在往下递的过程中一定会将新的节点放在叶子节点。 归: 归的过程是精髓,在一个节点一个节点的往回归的过程中
        //不断的更新节点的h,然后判断树是否平衡,如果不平衡就进行调平
        public AvlNode<K, V> add(AvlNode<K, V> cur, K key, V value) {
            if (cur == null) {
                return new AvlNode(key, value);
            }
            if (cur.key.compareTo(key) < 0) {
                cur.l = add(cur.l, key, value);
            } else {
                cur.r = add(cur.r, key, value);
            }
            cur.h = Math.max((cur.l == null ? 0 : cur.l.h), (cur.r == null ? 0 : cur.r.h)) + 1;
            //maintain()函数会自动的判断当前的树是否平衡,若不平衡就调整平衡。
            return maintain(cur);
        }

        //删除一个节点
        //在cur这棵树上,删掉key所代表的节点
        //返回cur这棵树的新头部
        //每次返回都要前调整树的结构
        public AvlNode<K, V> delete(AvlNode<K, V> cur, K key) {
            if (cur.key.compareTo(key) < 0) {
                cur.r = delete(cur.r, key);
            } else if (cur.key.compareTo(key) > 0) {
                cur.l = delete(cur.l, key);
            } else {
                //找到要删除的节点了
                if (cur.l == null && cur.r == null) {
                    //return null;
                    cur = null;
                } else if (cur.l != null && cur.r == null) {
                    //return cur.l; 不要在这里直接进行返回,每一次的返回都应该是调整好当前树的高度以后返回
                    cur = cur.l;
                } else if (cur.r != null && cur.l == null) {
                    //return cur.r;
                    cur = cur.r;
                } else {
                    //剩下的情况是左边不是null 右边也不是null
                    AvlNode<K, V> des = cur.l;
                    while (des.l != null) {
                        des = des.l;
                    }
                    cur.r = delete(cur.r, des.key);
                    des.l = cur.l;
                    des.r = cur.r;
                    //用des将cur替代
                    cur = des;
                }
            }
            cur.h = Math.max((cur.l == null ? 0 : cur.l.h), (cur.r == null ? 0 : cur.r.h)) + 1;
            return maintain(cur);
        }

        //调整平衡的方法
        //maintain()函数会自动的判断当前的树是否平衡,若不平衡就调整平衡。
        public AvlNode<K, V> maintain(AvlNode<K, V> cur) {
            if (cur == null) {
                return null;
            }
            int leftHeight = cur.l != null ? cur.l.h : 0;
            int rightHeight = cur.r != null ? cur.r.h : 0;
            if (Math.abs(leftHeight - rightHeight) > 1) {
                if (leftHeight > rightHeight) {
                    int leftleftHeight = cur.l != null && cur.l.l != null ? cur.l.l.h : 0;
                    int leftrightHeight = cur.l != null && cur.l.r != null ? cur.l.r.h : 0;
                    //leftleftHeight > leftrightHeight -- LL
                    //leftleftHeight == leftrightHeight -- LL + LR并存
                    //leftleftHeight < leftrightHeight -- LR
                    if (leftleftHeight >= leftrightHeight) {
                        cur = rightRotate(cur);//用cur来接住当前的头
                    } else {
                        cur.l = leftRotate(cur.l); //用cur.l把头接住
                        cur = rightRotate(cur); //用cur把头接住
                    }
                } else {
                    int rightleftHeight = cur.r != null && cur.r.l != null ? cur.r.l.h : 0;
                    int rightrightHeight = cur.r != null && cur.r.r != null ? cur.r.r.h : 0;
                    if (rightleftHeight >= rightrightHeight) {
                        cur = leftRotate(cur); //用cur来接住当前的头
                    } else {
                        cur.r = rightRotate(cur.r); //用cur.r把头接住
                        cur = leftRotate(cur); //用cur把头接住
                    }

                }
            }
            return cur;
        }

        //左旋 -- LL型 | LL+LR型 --> 统统左旋
        public AvlNode<K, V> rightRotate(AvlNode<K, V> cur) {
            AvlNode left = cur.l;
            cur.l = left.r;
            left.r = cur;
            cur.h = Math.max((cur.l != null ? cur.l.h : 0), (cur.r != null ? cur.r.h : 0));
            left.h = Math.max((left.l != null ? left.l.h : 0), (left.r != null ? left.r.h : 0));
            return left;
        }

        //右旋 -- RR型 | RR+RL型 --> 统统右旋
        public AvlNode<K, V> leftRotate(AvlNode<K, V> cur) {
            AvlNode right = cur.r;
            cur.r = right.l;
            right.l = cur;
            cur.h = Math.max((cur.l != null ? cur.l.h : 0), (cur.r != null ? cur.r.h : 0));
            right.h = Math.max((right.l != null ? right.l.h : 0), (right.r != null ? right.r.h : 0));
            return right;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HackerTerry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值