JDK 8 TreeSet 源码详解(完整版带详细注释)
1. 基本结构和常量定义
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable {
// 序列化版本号
private static final long serialVersionUID = -2479143000061671589L;
// 底层使用TreeMap存储元素,元素作为TreeMap的key存储,value为PRESENT对象
private transient NavigableMap<E,Object> m;
// TreeMap中value的占位符对象,所有元素都使用这个相同的值
private static final Object PRESENT = new Object();
}
2. 构造函数
/**
* 无参构造函数
* 构造一个空的TreeSet,元素按照自然排序进行排序
*/
public TreeSet() {
this(new TreeMap<E,Object>());
}
/**
* 指定比较器的构造函数
* @param comparator 比较器,用于定义元素的排序规则
*/
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
/**
* 从集合构造TreeSet
* @param c 要构造TreeSet的集合
* @throws NullPointerException 如果集合为null
*/
public TreeSet(Collection<? extends E> c) {
this();
addAll(c);
}
/**
* 从SortedSet构造TreeSet
* @param s 要构造TreeSet的SortedSet
*/
public TreeSet(SortedSet<E> s) {
this(s.comparator());
addAll(s);
}
/**
* 内部构造函数,用于初始化底层的NavigableMap
* @param m 底层的NavigableMap
*/
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}
3. 核心方法实现
3.1 add方法
/**
* 添加元素到TreeSet中
* @param e 要添加的元素
* @return 如果元素不存在则添加并返回true,如果元素已存在则返回false
*/
public boolean add(E e) {
// 调用NavigableMap的put方法,value始终为PRESENT对象
// 如果返回null说明是新添加的元素,否则说明元素已存在
return m.put(e, PRESENT) == null;
}
3.2 remove方法
/**
* 从TreeSet中移除指定元素
* @param o 要移除的元素
* @return 如果元素存在并被移除返回true,否则返回false
*/
public boolean remove(Object o) {
// 调用NavigableMap的remove方法,如果返回PRESENT说明元素存在并被移除
return m.remove(o) == PRESENT;
}
3.3 contains方法
/**
* 判断TreeSet是否包含指定元素
* @param o 要查找的元素
* @return 如果包含返回true,否则返回false
*/
public boolean contains(Object o) {
// 调用NavigableMap的containsKey方法
return m.containsKey(o);
}
3.4 size和isEmpty方法
/**
* 返回TreeSet中元素的数量
*/
public int size() {
return m.size();
}
/**
* 判断TreeSet是否为空
*/
public boolean isEmpty() {
return m.isEmpty();
}
3.5 clear方法
/**
* 清空TreeSet中的所有元素
*/
public void clear() {
m.clear();
}
4. 排序相关方法
4.1 比较器方法
/**
* 获取比较器
* @return 比较器,如果使用自然排序则返回null
*/
public Comparator<? super E> comparator() {
return m.comparator();
}
4.2 首尾元素方法
/**
* 获取第一个(最小)元素
* @return 第一个元素
* @throws NoSuchElementException 如果TreeSet为空
*/
public E first() {
return m.firstKey();
}
/**
* 获取最后一个(最大)元素
* @return 最后一个元素
* @throws NoSuchElementException 如果TreeSet为空
*/
public E last() {
return m.lastKey();
}
4.3 范围操作方法
/**
* 获取并移除第一个元素
* @return 第一个元素
* @throws NoSuchElementException 如果TreeSet为空
*/
public E pollFirst() {
Map.Entry<E,?> e = m.pollFirstEntry();
return (e == null) ? null : e.getKey();
}
/**
* 获取并移除最后一个元素
* @return 最后一个元素
* @throws NoSuchElementException 如果TreeSet为空
*/
public E pollLast() {
Map.Entry<E,?> e = m.pollLastEntry();
return (e == null) ? null : e.getKey();
}
5. 导航方法(NavigableSet接口)
5.1 下一个/上一个元素
/**
* 返回严格小于给定元素的最大元素
* @param e 给定元素
* @return 严格小于给定元素的最大元素,如果不存在返回null
*/
public E lower(E e) {
return m.lowerKey(e);
}
/**
* 返回小于或等于给定元素的最大元素
* @param e 给定元素
* @return 小于或等于给定元素的最大元素,如果不存在返回null
*/
public E floor(E e) {
return m.floorKey(e);
}
/**
* 返回大于或等于给定元素的最小元素
* @param e 给定元素
* @return 大于或等于给定元素的最小元素,如果不存在返回null
*/
public E ceiling(E e) {
return m.ceilingKey(e);
}
/**
* 返回严格大于给定元素的最小元素
* @param e 给定元素
* @return 严格大于给定元素的最小元素,如果不存在返回null
*/
public E higher(E e) {
return m.higherKey(e);
}
5.2 子集操作
/**
* 返回此set的部分视图,其元素范围从fromElement到toElement
* @param fromElement 起始元素(包含)
* @param toElement 结束元素(不包含)
* @return 指定范围的子集
*/
public SortedSet<E> subSet(E fromElement, E toElement) {
return new TreeSet<>(m.subMap(fromElement, true, toElement, false));
}
/**
* 返回此set的部分视图,其元素小于toElement
* @param toElement 结束元素(不包含)
* @return 小于指定元素的子集
*/
public SortedSet<E> headSet(E toElement) {
return new TreeSet<>(m.headMap(toElement, false));
}
/**
* 返回此set的部分视图,其元素大于或等于fromElement
* @param fromElement 起始元素(包含)
* @return 大于或等于指定元素的子集
*/
public SortedSet<E> tailSet(E fromElement) {
return new TreeSet<>(m.tailMap(fromElement, true));
}
/**
* 返回此set的部分视图,其元素范围从fromElement到toElement
* @param fromElement 起始元素
* @param fromInclusive 是否包含起始元素
* @param toElement 结束元素
* @param toInclusive 是否包含结束元素
* @return 指定范围的子集
*/
public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
E toElement, boolean toInclusive) {
return new TreeSet<>(m.subMap(fromElement, fromInclusive,
toElement, toInclusive));
}
/**
* 返回此set的部分视图,其元素小于(或等于)toElement
* @param toElement 结束元素
* @param inclusive 是否包含结束元素
* @return 小于(或等于)指定元素的子集
*/
public NavigableSet<E> headSet(E toElement, boolean inclusive) {
return new TreeSet<>(m.headMap(toElement, inclusive));
}
/**
* 返回此set的部分视图,其元素大于(或等于)fromElement
* @param fromElement 起始元素
* @param inclusive 是否包含起始元素
* @return 大于(或等于)指定元素的子集
*/
public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
return new TreeSet<>(m.tailMap(fromElement, inclusive));
}
5.3 反向操作
/**
* 返回此set的逆序视图
* @return 逆序视图
*/
public NavigableSet<E> descendingIterator() {
return m.descendingKeySet();
}
6. 迭代器实现
/**
* 返回迭代器(按升序)
*/
public Iterator<E> iterator() {
return m.navigableKeySet().iterator();
}
/**
* 返回逆序迭代器(按降序)
*/
public Iterator<E> descendingIterator() {
return m.descendingKeySet().iterator();
}
7. 其他重要方法
7.1 toArray方法
/**
* 返回包含所有元素的数组
*/
public Object[] toArray() {
return m.keySet().toArray();
}
/**
* 返回包含所有元素的指定类型数组
*/
public <T> T[] toArray(T[] a) {
return m.keySet().toArray(a);
}
7.2 clone方法
/**
* 克隆方法
*/
@SuppressWarnings("unchecked")
public Object clone() {
TreeSet<E> newSet = new TreeSet<>(m.comparator());
newSet.addAll(this);
return newSet;
}
7.3 Spliterator方法(Java 8新增)
/**
* 返回Spliterator(用于并行流操作)
*/
public Spliterator<E> spliterator() {
return m.keySet().spliterator();
}
8. 总结
8.1 TreeSet的特点
- 底层实现:基于TreeMap实现,元素作为TreeMap的key存储
- 有序性:保持元素的排序顺序(自然排序或自定义比较器)
- 唯一性:不允许存储重复元素
- 不允许null:如果使用自然排序,元素不能为null
- 非线程安全:不是线程安全的
- 高性能:基本操作(add、remove、contains)时间复杂度为O(log n)
8.2 时间复杂度分析
- 添加元素:O(log n)
- 删除元素:O(log n)
- 查找元素:O(log n)
- 遍历元素:O(n)
- 范围查询:O(log n + k),k为结果集大小
8.3 空间复杂度
- 存储空间:O(n) - n为存储的元素个数
- 额外空间:TreeMap需要额外的存储空间(红黑树结构)
8.4 TreeSet与TreeMap的关系
// TreeSet内部结构示意图:
// TreeSet中的元素e <--> TreeMap中的键值对(e, PRESENT)
// 其中PRESENT是一个共享的Object实例
8.5 使用建议
-
适用场景:
- 需要去除重复元素并保持排序
- 需要快速查找元素是否存在
- 需要频繁进行范围查询
- 需要找到最小/最大元素
-
不适用场景:
- 不需要排序功能(考虑使用HashSet)
- 需要快速随机访问(考虑使用ArrayList)
- 多线程环境(考虑使用Collections.synchronizedSortedSet()包装)
-
性能优化:
- 确保元素的compareTo()或比较器实现正确
- 选择合适的元素类型以获得良好的排序性能
- 对于大量数据的批量操作,可以考虑使用addAll()方法
8.6 关键设计思想
- 委托模式:TreeSet将大部分操作委托给内部的NavigableMap实现
- 占位符模式:使用固定的PRESENT对象作为TreeMap的value
- 适配器模式:将Map接口适配为Set接口
- 导航功能:实现了NavigableSet接口,提供丰富的导航方法
8.7 与其他Set实现的比较
特性 | HashSet | LinkedHashSet | TreeSet |
---|---|---|---|
底层实现 | HashMap | LinkedHashMap | TreeMap |
时间复杂度 | O(1) | O(1) | O(log n) |
空间复杂度 | O(n) | O(n) | O(n) |
排序 | 无序 | 插入顺序 | 自然排序/自定义排序 |
null元素 | 允许一个 | 允许一个 | 不允许(自然排序时) |
适用场景 | 一般用途 | 需要保持插入顺序 | 需要排序 |
TreeSet的设计体现了面向对象设计的精髓:简单、高效、易于理解和维护。通过组合TreeMap,TreeSet获得了优秀的排序功能和性能表现,同时保持了代码的简洁性。