集合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;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章