当前位置: 首页 > news >正文

Java:TreeSet的使用

目录

一、概念

二、常用操作

2.1 初始化排序规则

2.2 CRUD

2.3 遍历

2.4 自定义对象排序

2.5 实际应用示例:学生成绩

三、与HashSet对比


一、概念

TreeSet 实现了 Set 接口和 NavigableSet 接口(继承了 SortedSet 接口),基于 TreeMap 实现。TreeSet 中的元素是有序的,且不允许重复。

  • Set:首先,它是一个 Set,这意味着它不允许重复元素。如果你尝试添加一个已经存在的元素,add() 方法会返回 false

  • SortedSet:其次,它是一个 SortedSet,这意味着它会自动对其中所有元素进行排序

  • NavigableSet:它进一步提供了丰富的导航方法,例如查找“小于等于”、“大于等于”某个元素的最近元素等。

核心特点:

  • 有序性:元素按照自然顺序或指定的比较器进行排序

  • 唯一性:不允许重复元素

  • 基于红黑树:底层使用 TreeMap 实现,保证了高效的查找、插入和删除操作。红黑树是自平衡二叉查找树。

    • 二叉查找树 (BST):在 BST 中,每个节点都大于其左子树中的任意节点,且小于其右子树中的任意节点。这使得查找、插入和删除操作的平均时间复杂度为 O(log n)。

    • 自平衡:普通的 BST 在插入有序数据时会退化成链表,操作复杂度变为 O(n)。红黑树通过一套复杂的旋转和变色规则来确保树始终保持大致平衡,从而保证了最坏情况下,查找、插入、删除的时间复杂度也是 O(log n)

  • 非线程安全:需要外部同步才能在多线程环境中使用

注意事项:

  • 排序一致性:确保你的 Comparable 或 Comparator 实现与 equals() 逻辑一致,这是正确性的基础。

  • null 值:尽量避免向 TreeSet 中添加 null,除非你的比较器能明确处理它。

二、常用操作

2.1 初始化排序规则

// 使用自然排序(元素必须实现 Comparable 接口)
TreeSet<String> treeSet = new TreeSet<>();
treeSet.add("Orange");
treeSet.add("Apple");
treeSet.add("Banana");
// 输出:[Apple, Banana, Orange]
System.out.println(treeSet);// 使用自定义比较器
TreeSet<String> customTreeSet = new TreeSet<>((a, b) -> b.compareTo(a)); // 逆序
customTreeSet.add("Orange");
customTreeSet.add("Apple");
customTreeSet.add("Banana");
// 输出:[Orange, Banana, Apple]
System.out.println(customTreeSet);// 举例:按字符串长度排序
TreeSet<String> lengthSet = new TreeSet<>(new Comparator<String>() {@Overridepublic int compare(String s1, String s2) {int lenDiff = s1.length() - s2.length();// 如果长度相同,再用自然排序区分,否则会被视为相同元素而无法添加return (lenDiff != 0) ? lenDiff : s1.compareTo(s2);}
});

2.2 CRUD

// 添加元素
TreeSet<Integer> numbers = new TreeSet<>();
numbers.add(5);
numbers.add(2);
numbers.add(8);
numbers.add(1);
// 输出:[1, 2, 5, 8]
System.out.println(numbers);// 删除元素
numbers.remove(2); // 删除指定元素
numbers.pollFirst(); // 删除并返回第一个元素
numbers.pollLast(); // 删除并返回最后一个元素// 查询操作
TreeSet<Integer> set = new TreeSet<>();
for (int i = 1; i <= 10; i++) {set.add(i);
}
// 基本查询
System.out.println("First: " + set.first()); // 1
System.out.println("Last: " + set.last());   // 10
// 范围查询
System.out.println("HeadSet (<5): " + set.headSet(5));       // [1, 2, 3, 4]
System.out.println("TailSet (≥5): " + set.tailSet(5));       // [5, 6, 7, 8, 9, 10]
System.out.println("SubSet (3-7): " + set.subSet(3, 7));     // [3, 4, 5, 6]
// 邻近元素查询
System.out.println("Lower(5): " + set.lower(5));     // 4
System.out.println("Floor(5): " + set.floor(5));     // 5
System.out.println("Higher(5): " + set.higher(5));   // 6
System.out.println("Ceiling(5): " + set.ceiling(5)); // 5
方法描述
E first()返回当前集合中的第一个(最低)元素。
E last()返回当前集合中的最后一个(最高)元素。
E lower(E e)返回严格小于给定元素的最大元素,没有则返回 null
E floor(E e)返回小于等于给定元素的最大元素,没有则返回 null
E higher(E e)返回严格大于给定元素的最小元素,没有则返回 null
E ceiling(E e)返回大于等于给定元素的最小元素,没有则返回 null
E pollFirst()移除并返回第一个元素,如果集合为空则返回 null
E pollLast()移除并返回最后一个元素,如果集合为空则返回 null
NavigableSet<E> descendingSet()返回一个此集合的逆序视图。
Iterator<E> descendingIterator()返回一个逆序迭代器。
NavigableSet<E> headSet(E toElement, boolean inclusive)返回此集合中小于(或等于) toElement 的部分视图。
NavigableSet<E> tailSet(E fromElement, boolean inclusive)返回此集合中大于(或等于) fromElement 的部分视图。
NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive)返回此集合中从 fromElement 到 toElement 的范围视图。

2.3 遍历

// 使用迭代器
Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()) {System.out.println(iterator.next());
}// 使用增强for循环
for (Integer num : set) {System.out.println(num);
}// 使用降序迭代器
Iterator<Integer> descIterator = set.descendingIterator();
while (descIterator.hasNext()) {System.out.println(descIterator.next());
}

2.4 自定义对象排序

方法一:实现 Comparable 接口

要让自定义对象能够在 TreeSet 中正确排序,需要实现 Comparable 接口或提供 Comparator。

class Person implements Comparable<Person> {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic int compareTo(Person other) {return Integer.compare(this.age, other.age);}@Overridepublic String toString() {return name + "(" + age + ")";}
}// 使用
TreeSet<Person> people = new TreeSet<>();
people.add(new Person("Alice", 25));
people.add(new Person("Bob", 30));
people.add(new Person("Charlie", 20));// 输出:[Charlie(20), Alice(25), Bob(30)]
System.out.println(people);

方法二:使用 Comparator

TreeSet<Person> peopleByName = new TreeSet<>(Comparator.comparing(Person::getName)
);
peopleByName.add(new Person("Alice", 25));
peopleByName.add(new Person("Bob", 30));
peopleByName.add(new Person("Charlie", 20));// 输出:[Alice, Bob, Charlie]

2.5 实际应用示例:学生成绩

public class TreeSetExample {public static void main(String[] args) {// 创建一个存储学生成绩的TreeSetTreeSet<Student> students = new TreeSet<>(Comparator.comparing(Student::getScore).reversed().thenComparing(Student::getName));students.add(new Student("Alice", 85));students.add(new Student("Bob", 92));students.add(new Student("Charlie", 85));students.add(new Student("David", 78));// 输出前三名System.out.println("Top 3 students:");Iterator<Student> it = students.iterator();for (int i = 0; i < 3 && it.hasNext(); i++) {System.out.println((i + 1) + ". " + it.next());}// 查找成绩在80分以上的学生System.out.println("\nStudents with score ≥ 80:");Student dummy = new Student("", 80);for (Student s : students.tailSet(dummy)) {System.out.println(s);}}
}class Student {private String name;private int score;public Student(String name, int score) {this.name = name;this.score = score;}public String getName() { return name; }public int getScore() { return score; }@Overridepublic String toString() {return name + ": " + score;}
}

三、与HashSet对比

特性TreeSetHashSet
底层数据结构红黑树哈希表
元素顺序有序(按比较规则排序)无序(不保证迭代顺序)
addremovecontains 性能O(log n)O(1)(平均情况)
允许 null不允许(取决于Comparator)允许一个 null 元素
比较方式使用 compareTo() 或 Comparator使用 hashCode() 和 equals()
接口实现NavigableSetSortedSetSet

http://www.dtcms.com/a/352272.html

相关文章:

  • (Arxiv-2024)VideoMaker:零样本定制化视频生成,依托于视频扩散模型的内在力量
  • QT qml(quick3D)模型的移动
  • 专业解读《Light》封面:可调谐混合超表面(THCMs)如何革新下一代LiDAR系统
  • 3D游戏角色建模资源搜索指南(资料来源于网络)
  • 湖仓一体:小米集团基于 Apache Doris + Apache Paimon 实现 6 倍性能飞跃
  • JavaWeb之分布式事务规范
  • LInux(二十一)——Linux SSH 基于密钥交换的自动登录原理简介及配置说明
  • jenkins2025配置邮箱发送
  • 基于Android的车位预售预租APP/基于Android的车位租赁系统APP/基于Android的车位管理系统APP
  • Leetcode—1163. 按字典序排在最后的子串【困难】
  • Linux(二十二)——服务器初始化指南
  • cuda编程笔记(16)--使用 cuDNN 实现卷积、激活、池化等反向操作
  • 刀客doc:沃尔玛取消与TTD的独家合作,对程序化广告意味着什么?
  • 【RAGFlow代码详解-23】聊天系统架构
  • 字节跳动国际版 TRAE 深度解析:重新定义 AI 时代的编程体验
  • Docker化性能监控平台搭建:JMeter+InfluxDB+Grafana全攻略
  • Vite 模块联邦插件 实现微前端架构,其核心原理概述
  • 网络安全零基础入门:2025核心知识与系统学习路径分享
  • 工地考勤数据、监控回传与远程办公需求,如何通过贝锐蒲公英实现?
  • 做项目总是出问题,如何提升项目管理能力?
  • (MySQL索引事务) 本节目标 索引 事务
  • JUC之并发编程总结
  • 控制系统仿真之基础知识(一)
  • Nat Commun|“铃铛病”的空间多组学揭示基质细胞在疾病发生中的核心地位
  • 广告推荐模型1:逻辑回归(Logistic Regression,LR)
  • WebSocket实时通信系统——js技能提升
  • Linux 详谈软硬链接
  • 如何从零开始学习黑客技术?网络安全入门指南
  • Linux 系统配置 YUM 软件仓库
  • 【大语言模型 22】Tokenization深度技术:BPE、WordPiece、SentencePiece