Java Collections Framework 源码分析(4.2 - TreeSet)

Joshua

Java Collections Framework 源码分析(4.2 - TreeSet)

上一篇文章中介绍了 Set 接口和它的两个主要实现,HashSetLinkedHashSet。回忆一下它们的特点,HashSet 特点是无序,而 LinkedHashSet 则是有有序的,它的顺序是按照集合内元素的添加顺序。

它们具体的内部实现也较为简单,都是对两个 Map 数据结构的封装,应该都不难理解。

今天介绍的数据结构也同属于 Set 接口之下,同样不能存放相同的元素,但是最大的不同之处在于它是有顺序的,它就是 TreeSet

SortedSet

在开始分析源码之前还是先来看看 TreeSet 的类图:

0 (1).jpeg

从类图上看,出现了两个之前没有见过的接口,即 SortedSetNavigableSet 。让我们先来看看 SortedSet 的注释和源码。

注释给我们提供了以下的这些信息:

* `SortedSet` 是一个「有序」的集合,它的顺序由 `Comparable` 或是 `Comparator` 的结果决定。这意味着 `SortedSet` 容器内的元素必须实现这两个接口中的任一一个。
* 所有实现 `SortedSet` 接口的具体类,需要提供 4 个不同的构造函数,这里不再赘述,有兴趣的读者可以直接看这部分的注释。
* `SortedSet` 提供的部分获取某个范围元素的方法,都是前闭后开的。如果需要两个都是闭区间或是开区间,只能通过自己调整输入参数来控制。

现在我们已经了解了 SortedSetTreeSet 「有顺序」的意思了,接着就看看 SortedSet 接口上有哪些有意思的方法。

* `first`, `last` 方法分别是返回集合内第一个和最后一个元素。
* `headSet(E toElement)`  返回集合内所有小于 `toElement` 元素的集合,注意这里是开区间,是「小于」而不是「小于等于」。
* `tailSet(E fromElement)` 与 `headSet` 类似,返回所有大于等于 `fromElement` 元素的集合,注意这里是闭区间,即是「大于等于」。
* `subSet(E fromElement, E toElement)` 返回 `fromElement` 和 `toElement` 范围之间的元素集合,注意这里是前面提到的前闭后开区间,即「大于等于」`fromElement`,「小于」`toElement` 元素的集合。

SortedSet 关键方法就这些,准备进入下一个接口 NavigableSet 吧。

NavigableSet

NavigableSet 继承了 SortedSet 接口,并增加了数个方法,让我们逐一分析。

新增了 lower(E e)floor(E e)ceiling(E e)higher(E e) 四个方法,分别返回集合内「小于」,「小于等于」,「大于等于」,「大于」输入参数的 e 的元素,如果集合内没有符合条件的参数,则返回 null。

pollFirst()pollLast() 分别返回并移除集合中最小和最大的元素。

重载了父接口 SortedSet 中的 headSettailSetsubSet 这些方法,增加了额外的参数,控制区间的闭合,让方法更加方便使用,具体可以看对应的方法签名和注释。

剩下值得一提的是 descendingSet 方法,该方法会返回一个当前集合降序排列的视图,而注释中也提及通常情况下升序操作的性能好于降序。

TreeSet

其实写到这里 TreeSet 本身并没有太多值得分析的,因为它与 HashSet 一样,真正存储数据,并进行各种操作的是代理给了 TreeMap。基本上前面提到的所有方法都是直接掉用了 TreeMap 上的相关方法。看下面的代码片段:

private transient NavigableMap<E,Object> m;

public E last() {
    return m.lastKey();
}

public E pollFirst() {
    Map.Entry<E,?> e = m.pollFirstEntry();
    return (e == null) ? null : e.getKey();
}

public NavigableSet<E> headSet(E toElement, boolean inclusive) {
    return new TreeSet<>(m.headMap(toElement, inclusive));
}

额外可以从注释中了解的就是 addremovecontains 这几个方法的时间复杂度为 log(n)

欢迎关注我的微信号「且把金针度与人」,获取更多高质量文章
QR.png

阅读 859

Reading-Thinking-Sharing
编程 架构 设计 -- 你想要的这里都有
17 声望
13 粉丝
0 条评论
17 声望
13 粉丝
文章目录
宣传栏