Java TreeSet

一、TreeSet 基础概述

1.所属体系与底层结构

TreeSet 属于 Set 接口实现类,底层基于红黑树(平衡二叉搜索树),增删查综合性能优秀。

2. Set 通用两大特性(TreeSet 同样遵守)

  1. 元素不可重复;
  2. 集合无索引,不能通过下标遍历、取值。

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. 多字符串比较规则

  1. 从第一个字符开始逐位对比 ASCII;
  2. 某一位分出大小,直接判定整体大小,后面字符不再比较;
  3. 前缀相同、长度不同:短字符串更小;
    示例
    •"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 实现步骤

  1. 自定义实体类 implements Comparable<当前类>;
  2. 重写 public int compareTo(T o) 方法,自定义比较逻辑;
  3. 规则解读(重中之重)
    •this:当前准备添加的新元素
    •o:红黑树中已经存在的旧元素

返回值三种情况:

  1. 返回 负数:新元素更小,存入左子树;
  2. 返回 正数:新元素更大,存入右子树;
  3. 返回 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. 红黑树插入流程简述

  1. 第一个元素直接作为根节点(红黑树根强制黑色);
  2. 新元素从根节点开始,不断调用 compareTo 对比;
  3. 根据返回正负判断左 / 右子树,找到空位插入(新节点默认红色);
  4. 插入后校验红黑树五大规则,出现冲突自动左旋 / 右旋 / 变色平衡树结构。

方式二:比较器排序 Comparator(临时自定义规则)

1.使用场景

  1. 无法修改源码(如 String、Integer,不能改内部 compareTo);
  2. 同一实体需要多种排序规则,不想频繁修改实体类;

2. 实现步骤

  1. 使用带参构造 new TreeSet<>(Comparator实现类);
  2. 重写 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 集合整体选型总结(面试必背)

底层关联补充:

  1. HashSet 底层依托 HashMap;
  2. LinkedHashSet 底层依托 LinkedHashMap;
  3. 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。

相关推荐
编程风暴1 小时前
零基础数据分析项目模板+5条避坑红线
java·数据挖掘·数据分析
IKUN家族1 小时前
常见的依懒
java·服务器·数据库
m0_519196401 小时前
【设计模式】java的习题
开发语言·python
我命由我123451 小时前
Jetpack Compose - Material Design 断点范围、WindowSizeClass、针对不同屏幕尺寸创建预览、四类导航栏
android·java·开发语言·java-ee·kotlin·android jetpack·android runtime
linux-hzh2 小时前
百日算法修炼 · Day 05
java·算法
摇滚侠2 小时前
云原生 Java 架构师的第一课 K8s+Docker+KubeSphere+DevOps 89-129
java·云原生·kubernetes
snow@li2 小时前
SpringBoot:依赖注入(DI)全景深度梳理与实战分析/@Autowired、@Resource、@Qualifier
java·spring boot·rpc
captain3762 小时前
多线程进阶
java·开发语言·数据库
思麟呀2 小时前
C++(八):文件系统库+并行算法
开发语言·c++