Java集合·08·TreeMap详解

一、概述

TreeMap 是一个有序的key-value集合,它是通过红黑树实现的。

TreeMap 继承于AbstractMap,所以它是一个Map,即一个key-value集合。

TreeMap 实现了NavigableMap接口,意味着它支持一系列的导航方法。比如返回有序的key集合。

TreeMap 实现了Cloneable接口,意味着它能被克隆。

TreeMap 实现了java.io.Serializable接口,意味着它支持序列化。

SortedMap

扩展自Map接口,定义了有序的key-value键值对映射集合。根据key排序,使用Comparable或者Comparator进行排序。

特点:

  • key需要支持排序。

submap:

  • 1half-open they include their low* endpoint but not their high endpoint (where applicable)
  • 1closed range which includes both endpoints
  • 1open range which contains neither endpoint

定义API:

比较器相关:

  • comparator():Comparator

视图相关:

  • subMap(K, K): SortedMap
  • headMap(K): SortedMap
  • tailMap(K): SortedMap

定位相关:

  • firstKey(): K
  • lastKey(): K

NavigableMap

扩展自SortedMap接口,添加搜索相关API,支持顺序遍历和反序遍历

定位相关API(Entry/key):

  • lowerEntry(K): Entry
  • floorEntry(K): Entry
  • ceilingEntry(K): Entry
  • higherEntry(K): Entry
  • firstEntry(): Entry
  • lastEntry(): Entry

action:

  • pollFirstEntry(): Entry
  • pollLastEntry(): Entry

反序列表:

  • descendingMap():NavigableMap
  • descendingKeySet():NavigableSet

视图相关:

  • navigableKeySet(): NavigableSet
  • subMap(K, K):NavigableMap
  • headMap(K): NavigableMap
  • tailMap(K): NavigableMap

注意点:

NavigableMap中视图相关方法与SortedMap中视图相关方法不同,NavigableMap中返回类型为NavigableMap,SortedMap中返回类型为SortedMap

二、数据结构

TreeMap是通过红黑树实现的,TreeMap存储的是key-value键值对,TreeMap的排序是基于对key的排序。

使用链式结构存储元素,只记录root节点。使用size保存元素数量。

private transient TreeMapEntry root = null;
private transient int size = 0;

保存一个Comparator,同于key排序。

private final Comparator comparator;

TreeMapEntry

实现了Map.Entry接口,保存基本key、value信息。

持有父节点、左子节点、右子节点的引用。

记录本节点的颜色(红黑树需要)。

K key;
V value;
TreeMapEntry left = null;
TreeMapEntry right = null;
TreeMapEntry parent;
boolean color = BLACK;

红黑树(R-B Tree)

R-B Tree,全称是Red-Black Tree,又称为“红黑树”。

基本操作

  • 左旋
  • 右旋
  • 插入
  • 插入修正
  • 删除
  • 删除修正

时间复杂度:基本操作 containsKey、get、put 和 remove 的时间复杂度是 log(n)

三、特点

  • 有序,可使用Comparator进行排序,或者对key进行默认排序。
  • Iterator是fail-fast的
  • 非线程安全。可使用Collections.synchronizedSortedMap()
  • 性能稳定。基本操作 containsKey、get、put 和 remove 的时间复杂度是 log(n)
  • 对外Entry为snapshots,不可修改。
  • 不支持key为null值,value可以为null。

四、实现原理

1.基本方法

构造函数

四个:空构造函数、Comparator构造函数、Map构造函数、SortedMap构造函数

SortedMap构造函数:获取SortedMap的Comparator,设置为自身的Comparator

    public TreeMap(SortedMap m) {
        comparator = m.comparator();
        try {
            buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
        } catch (java.io.IOException cannotHappen) {
        } catch (ClassNotFoundException cannotHappen) {
        }
    }

基本操作

添加 - key不能为null,value不能为null,插入到红黑树中

删除 - getEntry(key),然后删除该节点

clear - 设置root为null,size为null

查询(见下面具体分类)

entry相关操作

查询:

getEntry:根据红黑树性质查找节点

    final TreeMapEntry 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 k = (Comparable) key;
        TreeMapEntry 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;
    }

firstEntry: 返回最left的节点

    final TreeMapEntry getFirstEntry() {
        TreeMapEntry p = root;
        if (p != null)
            while (p.left != null)
                p = p.left;
        return p;
    }

lastEntry: 返回最right的节点

    final TreeMapEntry getLastEntry() {
        TreeMapEntry p = root;
        if (p != null)
            while (p.right != null)
                p = p.right;
        return p;
    }

注意:

返回的entry并不是真实的元素,是新生的一个不可修改的entry,避免通过entry修改map结构

    static  Map.Entry exportEntry(TreeMapEntry e) {
        return (e == null) ? null :
            new AbstractMap.SimpleImmutableEntry<>(e);
    }

key相关操作

containsKey:使用Comparator比较key

    final TreeMapEntry getEntryUsingComparator(Object key) {
        @SuppressWarnings("unchecked")
            K k = (K) key;
        Comparator cpr = comparator;
        if (cpr != null) {
            TreeMapEntry p = root;
            while (p != null) {
                int cmp = cpr.compare(k, p.key);
                if (cmp < 0)
                    p = p.left;
                else if (cmp > 0)
                    p = p.right;
                else
                    return p;
            }
        }
        return null;
    }

value相关操作

containValue :使用了两个内部方法 successor(TreeMapEntry t)和predecessor(TreeMapEntry t),用于返回仅大于/小于当前entry的key的entry,通过这两个方法遍历map即根据key的顺序来便利map。

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

2.访问方式

PrivateEntryIterator

实现Iterator类,持有next和lastReturned两个指针。

        TreeMapEntry next;
        TreeMapEntry lastReturned;
        int expectedModCount;

支持前/后移动和查询、删除操作。

调用主类中的successor(e)和 predecessor(e)方法获取下一个/上一个entry。

EntryIterator

继承PrivateEntryIterator

next返回entry

KeyIterator

继承PrivateEntryIterator

next返回key

ValueIterator

继承PrivateEntryIterator

next返回value

DescendingKeyIterator

继承PrivateEntryIterator

next返回prevEntry

重写remove方法,删除前一个元素。

3.排序原理

默认排序,Comparable natural ordering of keys

Comparator排序

五、视图

支持四种视图,EntrySet、KeySet、Values和SubMap,SubMap又可分为顺序和逆序两种。

NavigableSubMap

继承AbstractMap,持有原NavigableMap的引用。记录lowKey、highKey或者直到Start、End,以及边缘值的包含关系。

        final TreeMap m;
        final K lo, hi;
        final boolean fromStart, toEnd;
        final boolean loInclusive, hiInclusive;

API

  • 支持大部分NavigableMap方法,通过调用原map实现。
  • 支持继续生成subMap。(Abstract)方法。
  • 包含自己的entrySet、keySet、values
  • 包含自己的Iterator

子类AscendingSubMap和DescendingSubMap,分别表示顺序和逆序。

EntrySet

继承AbstractSet>

调用原Map方法实现,Iterator返回EntryIterator

KeySet

继承AbstractSet>,实现NavigableSet接口。

调用原Map方法实现,Iterator返回KeyIterator/DescendingKeyIterator

Values

继承AbstractCollection

调用原Map方法实现

六、性能

时间复杂度:基本操作 containsKey、get、put 和 remove 的时间复杂度是 log(n)

证明过程略。

你可能感兴趣的:(Java集合·08·TreeMap详解)