Skip to content

Latest commit

 

History

History
246 lines (178 loc) · 7.67 KB

TreeMap源码分析.md

File metadata and controls

246 lines (178 loc) · 7.67 KB

简介

与HashMap相比,TreeMap是一个能比较元素大小的Map集合,会对传入的key进行了大小排序。其中,可以使用元素的自然顺序,也可以使用集合中自定义的比较器来进行排序;

TreeMap底层通过红黑树实现排序。

TreeMap具有如下特点:

  • 不允许出现重复的key;
  • 可以插入null键,null值;
  • 可以对元素进行排序;
  • 无序集合(插入和遍历顺序不一致);

TreeMap继承于AbstractMap,实现了Map, Cloneable, NavigableMap, Serializable接口。

(1)TreeMap 继承于AbstractMap,而AbstractMap实现了Map接口,并实现了Map接口中定义的方法,减少了其子类继承的复杂度;

(2)TreeMap 实现了Map接口,成为Map框架中的一员,可以包含着key--value形式的元素;

(3)TreeMap 实现了NavigableMap接口,意味着拥有了更强的元素搜索能力;

(4)TreeMap 实现了Cloneable接口,实现了clone()方法,可以被克隆;

(5)TreeMap 实现了Java.io.Serializable接口,支持序列化操作,可通过Hessian协议进行传输;

SortedMap

public interface SortedMap<K,V> extends Map<K,V> {
    
    //返回元素比较器。如果是自然顺序,则返回null;
    Comparator<? super K> comparator();
    
    //返回从fromKey到toKey的集合:含头不含尾
    java.util.SortedMap<K,V> subMap(K fromKey, K toKey);

    //返回从头到toKey的集合:不包含toKey
    java.util.SortedMap<K,V> headMap(K toKey);

    //返回从fromKey到结尾的集合:包含fromKey
    java.util.SortedMap<K,V> tailMap(K fromKey);
    
    //返回集合中的第一个元素:
    K firstKey();
   
    //返回集合中的最后一个元素:
    K lastKey();
    
    //返回集合中所有key的集合:
    Set<K> keySet();
    
    //返回集合中所有value的集合:
    Collection<V> values();
    
    //返回集合中的元素映射:
    Set<Map.Entry<K, V>> entrySet();
}

NavigableMap

public interface NavigableMap<K,V> extends SortedMap<K,V> {

    //返回小于key的第一个元素:
    Map.Entry<K,V> lowerEntry(K key);

    //返回小于key的第一个键:
    K lowerKey(K key);

    //返回小于等于key的第一个元素:
    Map.Entry<K,V> floorEntry(K key);

    //返回小于等于key的第一个键:
    K floorKey(K key);

    //返回大于或者等于key的第一个元素:
    Map.Entry<K,V> ceilingEntry(K key);

    //返回大于或者等于key的第一个键:
    K ceilingKey(K key);

    //返回大于key的第一个元素:
    Map.Entry<K,V> higherEntry(K key);

    //返回大于key的第一个键:
    K higherKey(K key);

    //返回集合中第一个元素:
    Map.Entry<K,V> firstEntry();

    //返回集合中最后一个元素:
    Map.Entry<K,V> lastEntry();

    //返回集合中第一个元素,并从集合中删除:
    Map.Entry<K,V> pollFirstEntry();

    //返回集合中最后一个元素,并从集合中删除:
    Map.Entry<K,V> pollLastEntry();

    //返回倒序的Map集合:
    java.util.NavigableMap<K,V> descendingMap();

    NavigableSet<K> navigableKeySet();

    //返回Map集合中倒序的Key组成的Set集合:
    NavigableSet<K> descendingKeySet();

    java.util.NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
                                       K toKey, boolean toInclusive);

    java.util.NavigableMap<K,V> headMap(K toKey, boolean inclusive);

    java.util.NavigableMap<K,V> tailMap(K fromKey, boolean inclusive);

    SortedMap<K,V> subMap(K fromKey, K toKey);

    SortedMap<K,V> headMap(K toKey);

    SortedMap<K,V> tailMap(K fromKey);
}

源码

TreeMap底层通过红黑树实现排序。红黑树的具体增删改查这里不详细说明,关于红黑树的教程可以看我写的笔记

红黑树

红黑树的英文是“Red-Black Tree”,简称 R-B Tree。它是一种不严格的平衡二叉查找树。

顾名思义,红黑树中的节点,一类被标记为黑色,一类被标记为红色。除此之外,一棵红黑树还需要满足这样几个要求:

  • 根节点是黑色的;
  • 每个叶子节点都是黑色的空节点(NIL),也就是说,叶子节点不存储数据;
  • 任何相邻的节点都不能同时为红色,也就是说,红色节点是被黑色节点隔开的;
  • 每个节点,从该节点到达其可达叶子节点的所有路径,都包含相同数目的黑色节点;

红黑树的高度近似$log _{2} n$,所以它是近似平衡,插入、删除、查找操作的时间复杂度都是 O(logn)。

红黑树结点结构

红黑树结点继承自Map.Entry<K,V>,多了左右孩子、父节点和颜色属性。

    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;
        }

        /**
         * Returns the key.
         *
         * @return the key
         */
        public K getKey() {
            return key;
        }

        /**
         * Returns the value associated with the key.
         *
         * @return the value associated with the key
         */
        public V getValue() {
            return value;
        }

        /**
         * Replaces the value currently associated with the key with the given
         * value.
         *
         * @return the value associated with the key before this method was
         *         called
         */
        public V setValue(V value) {
            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }

        public boolean equals(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<?,?> e = (Map.Entry<?,?>)o;

            return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
        }

        public int hashCode() {
            int keyHash = (key==null ? 0 : key.hashCode());
            int valueHash = (value==null ? 0 : value.hashCode());
            return keyHash ^ valueHash;
        }

        public String toString() {
            return key + "=" + value;
        }
    }

getEntry

看一些简单的代码,看懂红黑树代码意义也不大。

红黑树是二叉查找树,查找key比根结点小,就去左孩子查找;比根节点大,就去右孩子查找;如果相等,就返回结果。

    final Entry<K,V> getEntry(Object key) {
        // Offload comparator-based version for sake of performance
        if (comparator != null)
            return getEntryUsingComparator(key);
        if (key == null)
            throw new NullPointerException();
        @SuppressWarnings("unchecked")
            Comparable<? super K> k = (Comparable<? super K>) key;
        Entry<K,V> p = root;
        while (p != null) {
            int cmp = k.compareTo(p.key);
            if (cmp < 0)
                p = p.left;
            else if (cmp > 0)
                p = p.right;
            else
                return p;
        }
        return null;
    }

其他代码你们想看就看,感觉没啥意思,都是为了应付面试。如果懂红黑树插入、删除规则,看起来还是很简单的,代码不复杂。