• TreeMap,ThreeSet源码


    ThreeSet

      ThreeSet的底层就是ThreeMap

    public TreeSet() {
        this(new TreeMap<E,Object>());
    }

    ThreeMap

    1.ThreeMap参数

       //比较器
        private final Comparator<? super K> comparator;
    
        //根节点
        private transient Entry<K,V> root;
    
        //长度
        private transient int size = 0;
    
        //对树进行结构修改的次数
        private transient int modCount = 0;

    2.Entry参数

    K key;//
    V value;//
    Entry<K,V> left;//左子节点
    Entry<K,V> right;//右子节点
    Entry<K,V> parent;//父节点
    boolean color = BLACK;   //节点颜色     

    3.构造

    public TreeMap() {
       comparator = null;
    }

    4.put方法

    public V put(K key, V value) {
            //获取根节点
            Entry<K,V> t = root;
           //第一次进入,根节点为null
            if (t == null) {
                //验证key是否为空
                compare(key, key); // type (and possibly null) check
           //根据键值创建根节点
                root = new Entry<>(key, value, null);
            //size加一
                size = 1;
             //操作次数加加
                modCount++;
                return null;
            }
            int cmp;
         //创建父节点
            Entry<K,V> parent;
            //获得比较器 ,比较器在无参初始化的时候就是null,地下也没有给比较器赋值的地方
            Comparator<? super K> cpr = comparator;
            //判断比较器是否为空 
            if (cpr != null) {
                do {
                    parent = t;
                    cmp = cpr.compare(key, t.key);
                    if (cmp < 0)
                        t = t.left;
                    else if (cmp > 0)
                        t = t.right;
                    else
                        return t.setValue(value);
                } while (t != null);
            }
            else {//比较器为空进入
                //key为空抛出异常
                if (key == null)
                    throw new NullPointerException();
    
                    //这个注解是取消代码中的警告
                    @SuppressWarnings("unchecked")
                    //获取key
                    Comparable<? super K> k = (Comparable<? super K>) key;
    
                //循环执行找到当前节点的父节点
                do {
                    //根节点给父节点
                    parent = t;
                    //用当前的k和根节点的key进行比较 前面的小返回 负数
                    cmp = k.compareTo(t.key);
                    //k小于根节点的key 将根节点的左子节点给根节点
                    if (cmp < 0)
                        t = t.left;
                    else if (cmp > 0)
                        //k 大于根节点的key 将根节点的右子节点给根节点
                        t = t.right;
                    else
                        //相等的话证明是一致的key 直接修改根的值,并跳出循环
                        return t.setValue(value);
                //根不为空就向下进行循环,一直找到最后的节点为止
                } while (t != null);
            }
            //根据key value 和父节点 创建一个节点
            Entry<K,V> e = new Entry<>(key, value, parent);
            
            //根据上面的对比决定新节点放到左面还是右面
            if (cmp < 0)
                parent.left = e;
            else
                parent.right = e;
            //执行旋转
            fixAfterInsertion(e);
            size++;
            modCount++;
            return null;
        }

    验证key是否为空

     final int compare(Object k1, Object k2) {
            return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
                : comparator.compare((K)k1, (K)k2);
     }

    执行旋转

    //parentOf(x) 找到当前节点的父节点
    //leftOf(x) 找到当前节点的左节点
    //rightOf(x)找到当前节点的右节点
    //colorOf(x)找到当前节点的颜色
    //setColor(x,color) 设置当前节点的颜色
    //传入的是当前put的节点
    private void fixAfterInsertion(Entry<K,V> x) {
            //将当前节点设置为红色
            x.color = RED;
       
            //判断当前节点不是null 不是根节点 并且父节点的颜色是红色
            while (x != null && x != root && x.parent.color == RED) {
                //判断当前节点的父节点是 当前节点的爷爷节点的左边
                if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
                    //得到当前节点的爷爷节点的右节点,也就是叔叔节点
                    Entry<K,V> y = rightOf(parentOf(parentOf(x)));
                    //判断叔叔节点是红色
                    if (colorOf(y) == RED) {
                        //将父节点设置为黑色
                        setColor(parentOf(x), BLACK);
                        //将叔叔节点转为黑色
                        setColor(y, BLACK);
                        //将祖父节点设置为红色
                        setColor(parentOf(parentOf(x)), RED);
                        将祖父节点给当前节点,进行循环再次旋转
                        x = parentOf(parentOf(x));
                    } else {//当前节点的父节点在爷爷节点的右面
                        //判断当前节点在父节点的右面
                        if (x == rightOf(parentOf(x))) {
                            //将父节点给当前节点
                            x = parentOf(x);
                            //对父节点进行左旋
                            rotateLeft(x);
                        }
                        //将当前节点设置为黑色
                        setColor(parentOf(x), BLACK);
                        //将祖父节点设置为红色
                        setColor(parentOf(parentOf(x)), RED);
                        //对祖父节点进行右旋
                        rotateRight(parentOf(parentOf(x)));
                    }
                } else {//当前节点的父节点不在左面 祖父节点不是红色
                    //得到叔叔节点
                    Entry<K,V> y = leftOf(parentOf(parentOf(x)));
                    //判断叔叔节点是否是红色 
                    if (colorOf(y) == RED) {
                        //将父节点设置为黑色
                        setColor(parentOf(x), BLACK);
                        //将叔叔节点设置为黑色
                        setColor(y, BLACK);
                        //将爷爷节点设置为红色
                        setColor(parentOf(parentOf(x)), RED);
                        //将爷爷节点给当前节点,进入循环再次旋转
                        x = parentOf(parentOf(x));
                    } else {
                        //判断当前节点在父节点的左面
                        if (x == leftOf(parentOf(x))) {
                            //父节点等于当前节点
                            x = parentOf(x);
                            //对父节点进行右旋
                            rotateRight(x);
                        }
                        //将父节点设置为黑色
                        setColor(parentOf(x), BLACK);
                        //将爷爷节点设置为红色
                        setColor(parentOf(parentOf(x)), RED);
                        //将爷爷节点进行左旋
                        rotateLeft(parentOf(parentOf(x)));
                    }
                }
            }
            //将根节点设为黑色
            root.color = BLACK;
        }
    parentOf(x) 找到当前节点的父节点
    private static <K,V> Entry<K,V> parentOf(Entry<K,V> p) {
            return (p == null ? null: p.parent);
    }
    leftOf(x) 找到当前节点的左节点
    private static <K,V> Entry<K,V> leftOf(Entry<K,V> p) {
            return (p == null) ? null: p.left;
    }
    rightOf(x)找到当前节点的右节点
     private static <K,V> Entry<K,V> rightOf(Entry<K,V> p) {
            return (p == null) ? null: p.right;
    }
    colorOf(x)找到当前节点的颜色
    private static <K,V> boolean colorOf(Entry<K,V> p) {
            return (p == null ? BLACK : p.color);
    }
    setColor(x,color) 设置当前节点的颜色
    private static <K,V> void setColor(Entry<K,V> p, boolean c) {
            if (p != null)
                p.color = c;
    }
    rotateLeft 进行左旋
    /** From CLR */
    private void rotateLeft(Entry<K,V> p) {
            if (p != null) {
                Entry<K,V> r = p.right;
                p.right = r.left;
                if (r.left != null)
                    r.left.parent = p;
                r.parent = p.parent;
                if (p.parent == null)
                    root = r;
                else if (p.parent.left == p)
                    p.parent.left = r;
                else
                    p.parent.right = r;
                r.left = p;
                p.parent = r;
            }
    }
    rotateRight 进行右旋
    /** From CLR */
    private void rotateRight(Entry<K,V> p) {
            if (p != null) {
                Entry<K,V> l = p.left;
                p.left = l.right;
                if (l.right != null) l.right.parent = p;
                l.parent = p.parent;
                if (p.parent == null)
                    root = l;
                else if (p.parent.right == p)
                    p.parent.right = l;
                else p.parent.left = l;
                l.right = p;
                p.parent = l;
            }
    }
  • 相关阅读:
    win7下面安装VC6的SP5补丁
    共享一下, 国家授时中心服务器的IP地址
    修改默认调试器
    在做系统分析时,用到的几种对象之间的关系
    About SetClientSite in ActiveX
    我常用的Windbg命令
    字符编码笔记:ASCII,Unicode和UTF8(转) + BASE64
    Google Earth
    4.用条件属性而不是#if
    1.尽可能的使用属性,而不是数据成员
  • 原文地址:https://www.cnblogs.com/HQ0422/p/16225840.html
Copyright © 2020-2023  润新知