Java™ 教程(SortedSet接口)

6次阅读

共计 2970 个字符,预计需要花费 8 分钟才能阅读完成。

SortedSet 接口
SortedSet 是一个 Set,它按升序维护其元素,根据元素的自然顺序或根据 SortedSet 创建时提供的 Comparator 进行排序,除了常规的 Set 操作外,SortedSet 接口还提供以下操作:

范围视图 — 允许对已排序集进行任意范围操作。
端点 — 返回有序集合中的第一个或最后一个元素。
比较器访问 — 返回用于对集合进行排序的 Comparator(如果有)。

下面是 SortedSet 接口的代码。
public interface SortedSet<E> extends Set<E> {
// Range-view
SortedSet<E> subSet(E fromElement, E toElement);
SortedSet<E> headSet(E toElement);
SortedSet<E> tailSet(E fromElement);

// Endpoints
E first();
E last();

// Comparator access
Comparator<? super E> comparator();
}
Set 操作
SortedSet 从 Set 继承的操作在有序集和普通集上的行为相同,但有两个例外:

Iterator 操作返回的 iterator 按顺序遍历有序集。

toArray 返回的数组按顺序包含有序集的元素。

虽然接口不保证它,但 Java 平台的 SortedSet 实现的 toString 方法按顺序返回包含有序集的所有元素的字符串。
标准构造函数
按照惯例,所有通用 Collection 实现都提供了一个带有 Collection 的标准转换构造函数,SortedSet 实现也不例外,在 TreeSet 中,此构造函数创建一个实例,根据其自然顺序对其元素进行排序,这可能是一个错误,最好动态检查以查看指定的集合是否是 SortedSet 实例,如果是,则根据相同的标准(比较器或自然排序)对新 TreeSet 进行排序。因为 TreeSet 采用了它所采用的方法,所以它还提供了一个构造函数,它接受一个 SortedSet 并返回一个新的 TreeSet,它包含根据相同标准排序的相同元素。请注意,它是参数的编译时类型,而不是其运行时类型,它确定调用这两个构造函数中的哪一个(以及是否保留了排序条件)。
按照惯例,SortedSet 实现还提供了一个构造函数,它接受一个 Comparator 并返回一个根据指定的 Comparator 排序的空集,如果将 null 传递给此构造函数,则返回一个集合,该集合根据其自然顺序对其元素进行排序。
范围视图操作
范围视图操作有点类似于 List 接口提供的操作,但有一个很大的区别,即使直接修改了后备排序集,排序集的范围视图仍然有效,这是可行的,因为有序集的范围视图的端点是元素空间中的绝对点,而不是后备集合中的特定元素,如列表的情况。排序集的范围视图实际上只是集合的任何部分位于元素空间的指定部分中的窗口,对范围视图的更改将写回到后备排序集,反之亦然,因此,与列表上的范围视图不同,可以在很长一段时间内对已排序的集使用范围视图。
排序集提供三种范围视图操作,第一个 subSet 采用两个端点,如 subList,而不是索引,端点是对象,必须与有序集合中的元素相比较,使用 Set 的 Comparator 或其元素的自然顺序,无论 Set 使用哪个自定义,与 subList 一样,范围是半开放的,包括其低端点但不包括高端点。
因此,下面的代码行告诉你,包含在名为 dictionary 的字符串 SortedSet 中,“doorbell”和“pickle”之间有多少单词,包括“doorbell”,但不包括“pickle”:
int count = dictionary.subSet(“doorbell”, “pickle”).size();
以类似的方式,以下单行删除以字母 f 开头的所有元素。
dictionary.subSet(“f”, “g”).clear();
类似的技巧可以用来打印一个表格,告诉你每个字母开头有多少个单词。
for (char ch = ‘a’; ch <= ‘z’;) {
String from = String.valueOf(ch++);
String to = String.valueOf(ch);
System.out.println(from + “: ” + dictionary.subSet(from, to).size());
}
假设你要查看包含其两个端点的封闭间隔,而不是开放的间隔,如果元素类型允许计算元素空间中给定值的后继,则仅从 subSet 的 lowEndpoint 请求到 successor(highEndpoint),虽然它并不完全明显,但 String 的自然排序中的字符串 s 的后继是 s + “\0” — 也就是说,附加了空字符的 s。
因此,下面的单行告诉你“doorbell”和“pickle”之间有多少单词,包括 doorbell 和 pickle,都包含在字典中。
count = dictionary.subSet(“doorbell”, “pickle\0”).size();
可以使用类似的技术来查看不包含端点的开放间隔,从 lowEndpoint 到 highEndpoint 的开放间隔视图是从 successor(lowEndpoint) 到 highEndpoint 的半开放间隔,使用以下内容计算“doorbell”和“pickle”之间的单词数,不包括两者。
count = dictionary.subSet(“doorbell\0”, “pickle”).size();
SortedSet 接口包含另外两个范围视图操作 — headSet 和 tailSet,两者都采用单个 Object 参数,前者返回后备 SortedSet 的初始部分的视图,直到但不包括指定的对象,后者返回后备 SortedSet 的最后一部分的视图,从指定的对象开始,一直到后备 SortedSet 的末尾,因此,以下代码允许你将字典视为两个不相交的卷(a- m 和 n -z)。
SortedSet<String> volume1 = dictionary.headSet(“n”);
SortedSet<String> volume2 = dictionary.tailSet(“n”);
端点操作
SortedSet 接口包含返回有序集合中第一个和最后一个元素的操作,毫不奇怪被称为 first 和 last,除了它们的明显用途之外,last 还允许解决 SortedSet 接口中的不足。你想对 SortedSet 做的一件事就是进入 Set 的内部并向前或向后迭代,从内部向前迭代很容易:只需获取一个 tailSet 并迭代它,不幸的是,没有简单的方法可以倒退。
以下语法获得的元素空间中小于指定对象 o 的第一个元素。
Object predecessor = ss.headSet(o).last();
这是从排序集内部的一个点向后移动一个元素的好方法,它可以重复应用以向后迭代,但这是非常低效的,需要查找返回的每个元素。
Comparator 访问
SortedSet 接口包含一个名为 comparator 的访问器方法,它返回用于对集合进行排序的 Comparator,如果集合根据其元素的自然顺序排序,则为 null,提供此方法以便可以将排序的集合复制到具有相同排序的新排序集合中,它由前面描述的 SortedSet 构造函数使用。

上一篇:对象排序

正文完
 0