TreeSet的subSet和headSet是基于红黑树的动态视图,时间复杂度为O(log n)+O(m),不复制元素;subSet(from, to)返回[from, to)子集,headSet(to)返回

TreeSet 的 subSet 和 headSet 是基于底层红黑树结构实现的高效范围查询操作,时间复杂度为 O(log n)(构造视图)+ O(m)(遍历结果),不复制元素,仅返回动态视图。
subSet:获取指定区间的子集视图
subSet(fromElement, toElement) 返回一个包含从 fromElement(含)到 toElement(不含)之间所有元素的有序集合视图。该视图与原 TreeSet 共享数据,对视图的修改会反映到原集合(反之亦然),前提是元素可比较且范围合法。
- 必须确保
fromElement ≤ toElement,否则抛出IllegalArgumentException - 边界元素必须与 TreeSet 使用的 Comparator 兼容;若使用自然顺序,元素需实现
Comparable - 示例:
set.subSet(5, 10)返回 {5,6,7,8,9}(假设整数 TreeSet 包含这些值)
headSet:获取小于某值的所有元素
headSet(toElement) 返回一个包含所有严格小于 toElement 的元素的视图。它等价于 subSet(firstElement, toElement),但无需指定下界。
- 不包含
toElement本身,即使它存在于原集合中 - 支持带布尔参数的重载方法:
headSet(toElement, inclusive),可选择是否包含边界值 - 若
toElement小于 TreeSet 中最小元素,返回空视图
底层红黑树如何支撑高效范围查询
TreeSet 底层由 TreeMap(红黑树)驱动,节点按 key 有序排列。执行 subSet 或 headSet 时,JDK 并不遍历全部节点,而是通过二分查找快速定位边界节点位置,再以中序方式惰性遍历目标区间。
- 查找起始/结束节点耗时 O(log n),后续迭代每个元素为 O(1) 均摊成本
- 返回的是
NavigableSubMap或其子类(如AscendingSubMap),封装了左右边界引用和方向信息 - 视图是“实时”的——原集合增删符合条件的元素,视图立即可见;删除视图中元素也会同步更新原集合
使用注意事项与常见陷阱
这些视图看似轻量,但误用易引发 ConcurrentModificationException 或逻辑错误。
- 禁止在迭代子集视图的同时,通过原 TreeSet 修改不在该视图内的元素——这可能破坏红黑树结构或导致遍历异常
- 若原 TreeSet 使用自定义 Comparator,请确保
fromElement和toElement可被该 Comparator 比较,否则运行时报ClassCastException - 视图不可序列化独立于原 TreeSet;反序列化时需保证原集合仍存在且未被修改
- 避免长期缓存子集视图并反复使用——它不快照数据,行为依赖原集合当前状态

















