TreeSet 与 NavigableSet
存储有序且不重复的元素,并使用 floor、ceiling、higher 和 lower 查询最近邻元素
TreeSet 与 NavigableSet 是 CoddyKit 上的免费 Java Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。
什么是 TreeSet?
TreeSet 是一种由红黑树支持的有序集合。它按升序自然顺序(或指定的 Comparator)存储不重复的元素。所有操作的复杂度均为 O(log n)。
import java.util.TreeSet;
TreeSet<String> names = new TreeSet<>();
names.add("Charlie");
names.add("Alice");
names.add("Bob");
names.add("Alice"); // duplicate ignored
for (String s : names) System.out.print(s + " ");
// Alice Bob CharlieNavigableSet 方法:floor、ceiling、lower、higher
TreeSet 实现了 NavigableSet,提供用于查找最接近元素的导航方法:
TreeSet<Integer> set = new TreeSet<>();
for (int i = 10; i <= 50; i += 10) set.add(i);
// {10, 20, 30, 40, 50}
System.out.println(set.floor(25)); // 20 (greatest ≤ 25)
System.out.println(set.ceiling(25)); // 30 (smallest ≥ 25)
System.out.println(set.lower(30)); // 20 (strictly less)
System.out.println(set.higher(30)); // 40 (strictly greater)first、last、pollFirst、pollLast
访问或移除边界元素:
TreeSet<String> ts = new TreeSet<>(Set.of("cherry","apple","banana","date"));
System.out.println(ts.first()); // apple
System.out.println(ts.last()); // date
System.out.println(ts.pollFirst()); // apple (removed)
System.out.println(ts.pollLast()); // date (removed)
System.out.println(ts); // [banana, cherry]headSet、tailSet、subSet
提取有序的子集视图:
TreeSet<Integer> set = new TreeSet<>(Set.of(1,2,3,4,5,6,7,8,9,10));
System.out.println(set.headSet(5)); // [1, 2, 3, 4]
System.out.println(set.tailSet(7)); // [7, 8, 9, 10]
System.out.println(set.subSet(3, 7)); // [3, 4, 5, 6]
// Inclusive upper bound:
System.out.println(set.subSet(3, true, 7, true)); // [3,4,5,6,7]降序遍历
使用 descendingIterator() 或 descendingSet() 实现逆序:
TreeSet<Integer> ts = new TreeSet<>(Set.of(1,3,5,7,9));
// Descending iterator
var it = ts.descendingIterator();
while (it.hasNext()) System.out.print(it.next() + " ");
// 9 7 5 3 1通过 Comparator 自定义顺序
传入 Comparator,按非自然顺序排序——例如让最长字符串排在最前面:
TreeSet<String> byLength = new TreeSet<>(
Comparator.comparingInt(String::length)
.thenComparing(Comparator.naturalOrder())
);
byLength.add("Hi");
byLength.add("Hello");
byLength.add("Hey");
byLength.add("Java");
for (String s : byLength) System.out.print(s + " ");
// Hi Hey Java Hello使用场景:有序的不重复用户名
将用户名存储在 TreeSet 中,即可自动去重并保持字母顺序:
TreeSet<String> users = new TreeSet<>();
users.add("alice");
users.add("bob");
users.add("alice"); // ignored
users.add("carol");
System.out.println(users.first()); // alice
System.out.println(users); // [alice, bob, carol]使用场景:范围计数
使用 subSet 统计范围内的元素数量:
TreeSet<Integer> scores = new TreeSet<>();
for (int s : new int[]{45,62,78,55,90,88,34,71}) scores.add(s);
// Scores between 60 and 89 (inclusive)
int count = scores.subSet(60, true, 89, true).size();
System.out.println("Students in B range: " + count); // 3 (62, 78, 88... wait: 62,78,71,88=4)
// Actually: 62,71,78,88 = 4TreeSet 与 HashSet、LinkedHashSet
请根据需求选择:
- HashSet:操作复杂度为 O(1),无序
- LinkedHashSet:操作复杂度为 O(1),按插入顺序排列
- TreeSet:操作复杂度为 O(log n),有序,并提供导航方法
TreeSet 要求元素实现 Comparable 或提供 Comparator。
空值元素
TreeSet 在使用自然顺序时不允许(NOT)空值元素——因为空值无法比较,所以会抛出 NullPointerException。显式处理空值的自定义 Comparator 可以正常工作。
TreeSet<String> ts = new TreeSet<>();
try {
ts.add(null); // throws NullPointerException
} catch (NullPointerException e) {
System.out.println("Cannot add null: " + e);
}线程安全
TreeSet 不是线程安全的。请使用 Collections.synchronizedSortedSet() 在外部进行同步,或者使用同时有序且线程安全的 ConcurrentSkipListSet。
快速检查
一个 TreeSet<Integer> 包含 {10, 20, 30, 40, 50}。set.ceiling(35) 会返回什么?
回顾:TreeSet 与 NavigableSet
要点:
- TreeSet 存储不重复的有序元素(O(log n))
- 实现 NavigableSet:floor、ceiling、lower、higher、first、last
- headSet、tailSet、subSet 返回由原映射支持的范围视图
- 使用 descendingSet()/descendingIterator() 实现逆序
- 不是线程安全的——并发使用请改用 ConcurrentSkipListSet
常见问题解答
「TreeSet 与 NavigableSet」课时是免费的吗?
是的 — 「TreeSet 与 NavigableSet」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。
「TreeSet 与 NavigableSet」这节课中我会学到什么?
存储有序且不重复的元素,并使用 floor、ceiling、higher 和 lower 查询最近邻元素 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Java Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「TreeSet 与 NavigableSet」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Java Academy 课中编写并运行代码吗?
能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- TreeMap:有序键值对
- 子映射与范围视图
- TreeSet 与 NavigableSet
- Tree 集合中的自定义排序