集合TreeMap原理刨解JDK1.8(7)

HashMap对象没有顺序,TreeMap实现是排序平衡二叉树,大致是红黑树,树可以排序。根据根节点比较左小右大的特点,注意的是按键排序,值不排序

对象只要实现comparable可以排序,重写compareTo(Object obj) 实现排序。类不能实现可以使用Compartor这个比较器必须实现compare(String o1, String o2)方法

构造方法
1.第一个默认TreeMap类,比较自定义对象要实现Comparabe接口比较器,重写compareTo方法
2.第二个比较TreeMap参数要接收Compartor比较器对象。重写Compartor接口中compare方法,比较灵活

    public TreeMap() {
        comparator = null;
    }
    public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }

TreeMap的简单使用,按键字母正排序,String.CASE_INSENSITIVE_ORDER实现比较器忽视大小写,像String内部有比较器。
在这里插入图片描述
倒过来排序,实现Comparator比较器就可以,compare()返回int类型,方法参数o1是第一个对象,o2第二个对象交换对象。默认去重复,如果想不去重复,比较器可以改
在这里插入图片描述
更简单的用法,调用Collections静态方法排序

        //正序
        Map<String, String> map = new TreeMap<>(Collections.reverseOrder());
        //倒序
//        Map<String, String> map = new TreeMap<>(
//                Collections.reverseOrder(String.CASE_INSENSITIVE_ORDER));
        map.put("4", "李");
        map.put("4", "波");
        map.put("3", "勇");
        map.put("2", "22");
        for (Map.Entry<String, String> kv : map.entrySet()) {
            System.out.print("键:"+kv.getKey() + "=" + "值:"+kv.getValue()+"|");
        }

重写比较器按时间排序,不是字符串排序
在这里插入图片描述
实现原理大致是
红黑树可看做平衡排序二叉树,

	//比较器是构造方法传过来的,没传默认null
    private final Comparator<? super K> comparator;
    //指向树的根节点,下面Entry
    private transient Entry<K,V> root;
    private transient int size = 0;
    /**
     * The number of structural modifications to the tree.
     * 树的结构修改数
     */
    private transient int modCount = 0;

这静态内部类Entry由外部root对象引用。由根节点访问下面每一个节点Entry

    static final class Entry<K,V> implements Map.Entry<K,V> {
        K key;
        V value;
        //节点引用左边
        Entry<K,V> left;
        //节点引用右边
        Entry<K,V> right;
        //父节点
        Entry<K,V> parent;
        //节点颜色,默认根节点是黑色
        boolean color = BLACK;
        /**
         * Make a new cell with given key, value, and parent, and with
         * {@code null} child links, and BLACK color.
         */
        Entry(K key, V value, Entry<K,V> parent) {
            this.key = key;
            this.value = value;
            this.parent = parent;
        }

put()添加方法,首先添加前compare()检查key的类型和null。第一次添加判断是null创建Entry节点,指向root根节点

   public V put(K key, V value) {
        Entry<K,V> t = root;
        if (t == null) {
            compare(key, key); // type (and possibly null) check
            root = new Entry<>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }

添加方法下面根据比较器comparatorComparable来区分保存值,默认指向父节点,从父节点比较输入的key 和 引用key,小于根节点,将t节点设置左,大于根节点将t设置到右边。setValue()有重复的值,设置返回。循环结束t = null 。

		//保存比较结果
  		int cmp;
  		//父节点
        Entry<K,V> parent;
        //比较器
        Comparator<? super K> cpr = comparator;
        if (cpr != null) { //实现比较器Comparator
            do {
            	//开始t节点指向父节点
                parent = t;
                //从根节点比较键
                cmp = cpr.compare(key, t.key);
                //小于根节点,将t设置左边
                if (cmp < 0)
                    t = t.left;
                 //大于根节点,将t设置到右边
                else if (cmp > 0)
                    t = t.right;
                else
                //比较有这个键返回设置值
                    return t.setValue(value);
                //t null退出循环    
            } while (t != null);
        }
        else { //Comparable实现比较器
            if (key == null)
                throw new NullPointerException();
            @SuppressWarnings("unchecked")
                Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                //compareTo比较
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        //上面步骤找到父节点后,就是新建一个节点,k / v 根
        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;
    }

get()方法根据键获取值,通过p找到值value

    public V get(Object key) {
        Entry<K,V> p = getEntry(key);
        return (p==null ? null : p.value);
    }

containsValue()方法根据值获取通过for循环,找到返回true,valEquals比较里面是equals

 public boolean containsValue(Object value) {
        for (Entry<K,V> e = getFirstEntry(); e != null; e = successor(e))
            if (valEquals(value, e.value))
                return true;
        return false;
    }

在这里插入图片描述
remove()删除方法。底层deleteEntry()方法删除键,删除修改指向,给赋nul,l分为左和右以及根节点。

    public V remove(Object key) {
        Entry<K,V> p = getEntry(key);
        if (p == null)
            return null;
        V oldValue = p.value;
        deleteEntry(p); //重要方法
        return oldValue;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章