一、TreeSet 基础概述
1.所属体系与底层结构
TreeSet 属于 Set 接口实现类,底层基于红黑树(平衡二叉搜索树),增删查综合性能优秀。
2. Set 通用两大特性(TreeSet 同样遵守)
- 元素不可重复;
- 集合无索引,不能通过下标遍历、取值。
3. TreeSet 独有核心特点
自动对存储元素升序排序(默认从小到大),无需手动排序;
无新增独有方法,全部复用 Collection、Set 接口提供的通用方法。
二、基础使用:存储基本包装类型(Integer、Double)
1.注意点
集合不能存基本数据类型(int/double),必须使用对应包装类(Integer/Double)。
2. 示例代码:存储 Integer 并打印
java
import java.util.TreeSet;
public class TreeSetDemo1 {
public static void main(String[] args) {
TreeSet<Integer> ts = new TreeSet<>();
// 乱序添加
ts.add(5);
ts.add(3);
ts.add(1);
ts.add(4);
ts.add(2);
// 直接打印集合,自动升序输出 [1,2,3,4,5]
System.out.println(ts);
}
}
3.TreeSet 三种遍历方式(全部兼容 Set)
方式 1:迭代器遍历
java
Iterator<Integer> it = ts.iterator();
while(it.hasNext()){
Integer i = it.next();
System.out.println(i);
}
•hasNext():判断是否还有下一个元素
•next():指针后移 + 返回当前元素;JDK5 + 自动装箱,int 接收也可行
方式 2:增强 for 循环(最简洁)
java
for(Integer t : ts){
System.out.println(t);
}
方式 3:forEach + Lambda 表达式
1)原始匿名内部类写法
java
ts.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer i) {
System.out.println(i);
}
});
2)简化 Lambda 写法(Consumer 是函数式接口)
java
ts.forEach(i -> System.out.println(i));
底层原理:forEach 内部依然是增强 for 遍历,依次把元素传入 accept 方法。
三、存储字符、字符串的默认排序规则
1.字符排序
按照 ASCII 码数值升序 排列(表象和字典序一致,但底层依据 ASCII)
例:'A'(65) < 'B'(66),集合会自动按 A、B、C 排序。
2. 多字符串比较规则
- 从第一个字符开始逐位对比 ASCII;
- 某一位分出大小,直接判定整体大小,后面字符不再比较;
- 前缀相同、长度不同:短字符串更小;
示例 :
•"AAA" vs "AB":第二位 A<B → "AAA" 靠前
•"AB" vs "ABA":前两位相同,AB 更短 → AB 靠前
•"ABA" vs "CD":首位 A<C → ABA 靠前
底层原理
String 类默认实现 Comparable 接口,重写 compareTo 方法,自带 ASCII 比较逻辑。
四、TreeSet 两种排序规则(核心考点)
前置问题 :存储自定义对象直接 add 会报错
自定义类(Student)没有默认比较规则,TreeSet 不知道如何排序,运行抛出异常。
解决方案二选一 :
1.自然排序(Comparable):实体类实现接口,默认规则;
2.比较器排序(Comparator):创建集合时传入,临时自定义规则;
优先级:比较器 Comparator > 自然 Comparable,两者同时存在以比较器为准。
方式一:自然排序 Comparable(默认方案)
1 实现步骤
- 自定义实体类 implements Comparable<当前类>;
- 重写 public int compareTo(T o) 方法,自定义比较逻辑;
- 规则解读(重中之重)
•this:当前准备添加的新元素
•o:红黑树中已经存在的旧元素
返回值三种情况:
- 返回 负数:新元素更小,存入左子树;
- 返回 正数:新元素更大,存入右子树;
- 返回 0:判定两个元素重复,舍弃不存入集合。
2. 代码示例:Student 类按年龄升序
实体类 Student
java
public class Student implements Comparable<Student> {
private String name;
private int age;
// 空参、全参构造、get/set、toString
public Student(){}
public Student(String name,int age){
this.name = name;
this.age = age;
}
@Override
public int compareTo(Student o) {
// 按年龄升序:新age - 已有age
return this.age - o.age;
}
// getter & setter & toString
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
@Override
public String toString() {
return "Student{name='" + name + "', age=" + age + "}";
}
}
测试类
java
TreeSet<Student> ts = new TreeSet<>();
ts.add(new Student("张三",23));
ts.add(new Student("王五",25));
ts.add(new Student("李四",24));
// 输出自动按年龄 23、24、25排序
System.out.println(ts);
3.补充重要知识点
TreeSet 底层是红黑树,不需要重写 hashCode ()、equals ();
hashCode/equals 是 HashSet(哈希表)去重依赖,和 TreeSet 无关。
4. 红黑树插入流程简述
- 第一个元素直接作为根节点(红黑树根强制黑色);
- 新元素从根节点开始,不断调用 compareTo 对比;
- 根据返回正负判断左 / 右子树,找到空位插入(新节点默认红色);
- 插入后校验红黑树五大规则,出现冲突自动左旋 / 右旋 / 变色平衡树结构。
方式二:比较器排序 Comparator(临时自定义规则)
1.使用场景
- 无法修改源码(如 String、Integer,不能改内部 compareTo);
- 同一实体需要多种排序规则,不想频繁修改实体类;
2. 实现步骤
- 使用带参构造 new TreeSet<>(Comparator实现类);
- 重写 int compare(O1,O2)
○O1:待添加新元素
○O2:树中已有元素
返回值规则和 Comparable 完全一致(负左、正右、0 去重)。
示例:字符串先按长度升序,长度相同按 ASCII 字典序
java
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSetDemo3 {
public static void main(String[] args) {
// Lambda简化Comparator写法
TreeSet<String> ts = new TreeSet<>((o1, o2) -> {
// 先比较长度
int len = o1.length() - o2.length();
// 长度相同,使用字符串默认规则
return len == 0 ? o1.compareTo(o2) : len;
});
ts.add("C");
ts.add("AB");
ts.add("DF");
ts.add("QWER");
System.out.println(ts);
}
}
五、综合复杂案例:多条件多级排序
需求
存储学生(姓名、年龄、语文、数学、英语),排序优先级从高到低:
1.总分降序;
2.总分相同 → 语文升序;
3.语文相同 → 数学升序;
4.数学相同 → 英语升序;
5.英语相同 → 年龄升序;
6.年龄相同 → 姓名字母升序;
所有属性完全一致判定为重复,不存入。
核心 compareTo 逻辑(自然排序)
java
@Override
public int compareTo(StudentR o) {
// 1.计算两人总分
int sum1 = this.chinese + this.math + this.english;
int sum2 = o.chinese + o.math + o.english;
// 总分降序:反过来 o.sum - this.sum
int i = sum2 - sum1;
if(i == 0){
// 总分相等,比语文升序
i = this.chinese - o.chinese;
if(i == 0){
// 语文相等,比数学
i = this.math - o.math;
if(i == 0){
// 数学相等,比英语
i = this.english - o.english;
if(i == 0){
// 成绩全相同,比年龄
i = this.age - o.age;
if(i == 0){
// 年龄相同,比姓名字母
i = this.name.compareTo(o.name);
}
}
}
}
}
return i;
}
六、Set 集合整体选型总结(面试必背)

底层关联补充:
- HashSet 底层依托 HashMap;
- LinkedHashSet 底层依托 LinkedHashMap;
- TreeSet 底层依托 TreeMap;
Set 本质是复用 Map 的 key 实现元素存储,value 占位空值。
七、全书核心背诵要点
1.TreeSet 底层红黑树,元素唯一、无索引、自动排序;
2.排序两种方式:
○Comparable:实体类实现,默认规则;
○Comparator:创建集合传入,临时规则,优先级更高;
3.compareTo/compare 返回值规则:负存左、正存右、0 去重;
4.存储自定义对象必须指定比较规则,否则运行报错;
5.TreeSet 不需要重写 hashCode、equals;HashSet 才需要;
6.字符串排序底层依据 ASCII 码逐位对比;
7.开发选型:仅去重用 HashSet;要排序用 TreeSet;要有序去重用 LinkedHashSet。