【Java 基础篇】Java TreeSet 详解:红黑树实现的有序集合

news2024/9/20 16:50:43

在这里插入图片描述

Java 集合框架提供了多种数据结构,用于存储和操作数据。其中,TreeSet 是一种特殊类型的集合,它通过红黑树(Red-Black Tree)数据结构实现了有序的、唯一元素存储。本篇博客将深入探讨 TreeSet,包括其概念、特性、内部实现、使用方法以及示例代码。无论您是初学者还是有一定经验的 Java 开发者,都能在这里找到有关 TreeSet 的有用信息。

1. 什么是 TreeSet?

1.1. 集合的基本概念

在开始介绍 TreeSet 之前,我们先来回顾一下集合的基本概念。

集合是 Java 编程中常用的数据结构之一,它用于存储一组对象。集合通常分为两大类:

  • 有序集合(Ordered Collection):其中的元素按照某种顺序排列,可以是添加顺序、自然顺序或自定义顺序。
  • 无序集合(Unordered Collection):其中的元素没有明确定义的顺序。

集合可以用于存储不同类型的数据,例如整数、字符串、对象等。在使用集合时,我们通常关心以下几个方面的问题:

  • 唯一性:集合是否允许重复元素。
  • 有序性:集合中的元素是否有顺序。
  • 性能:在集合中执行常见操作的性能,如添加、删除、查找等。

1.2. TreeSet 的定义

TreeSet 是 Java 集合框架中的一种有序集合,它实现了 Set 接口,因此具有不允许重复元素的特性。与 HashSet 不同,TreeSet 使用红黑树数据结构来存储元素,这使得元素在集合中保持有序。

这里需要理解两个主要特性:

  • 有序性(Order):TreeSet 中的元素按照自然排序(元素的自然顺序)或者指定的排序方式(通过比较器)排列。这意味着您可以遍历 TreeSet 得到的元素是按照一定的顺序排列的。
  • 唯一性(Uniqueness):与 HashSet 一样,TreeSet 也保证元素的唯一性,不允许重复元素。

因此,TreeSet 是一个适用于需要有序存储唯一元素的场景的理想选择。

2. TreeSet 的内部实现

要深入理解 TreeSet,我们需要了解它的内部实现机制,即红黑树。红黑树是一种自平衡二叉搜索树(Self-Balancing Binary Search Tree),它具有以下特性:

  • 每个节点要么是红色,要么是黑色。
  • 根节点是黑色。
  • 每个叶子节点(NIL 节点,空节点)是黑色的。
  • 如果一个节点是红色的,则它的两个子节点都是黑色的。
  • 从任意节点到其每个叶子节点的所有路径都包含相同数目的黑色节点。

这些规则确保了树的平衡,从而保证了树的高度不会过高,使得查找、插入和删除操作的性能稳定。

TreeSet 中,元素被存储在红黑树的节点中,根据元素的大小关系构建树结构。这意味着,插入、删除和查找操作的时间复杂度为 O(log n),其中 n 是集合中的元素个数。由于红黑树的平衡性质,这些操作的性能是可预测的。

3. TreeSet 的创建与初始化

要使用 TreeSet,首先需要创建和初始化它。以下是一些常见的初始化方法:

3.1. 默认构造函数

使用默认构造函数创建一个空的 TreeSet 对象:

TreeSet<String> treeSet = new TreeSet<>();

这将创建一个初始容量为 16 的 TreeSet,加载因子为 0.75。您可以根据需要调整这些参数。

3.2. 指定排序方式的构造函数

您可以使用带有 Comparator 参数的构造函数来指定元素的排序方式。比如,创建一个降序排列的 TreeSet

TreeSet<Integer> customOrderTreeSet = new TreeSet<>(Comparator.reverseOrder());

3.3. 从现有集合创建

您还可以从现有的集合(如 ListSet)创建一个 TreeSet,以便在不同集合类型之间进行转换:

Set<String> existingSet = new HashSet<>(Arrays.asList("A", "B", "C"));
TreeSet<String> treeSetFromSet = new TreeSet<>(existingSet);

这将使用现有集合中的元素来初始化新的 TreeSet

4. 基本操作:添加、删除和查询元素

TreeSet 提供了常见的集合操作,包括添加、删除和查询元素。以下是一些基本操作的示例:

4.1. 添加元素

使用 add 方法来向 TreeSet 中添加元素:

treeSet.add("D");
treeSet.add("E");

4.2. 删除元素

使用 remove 方法来从 TreeSet 中删除元素:

treeSet.remove("B");

4.3. 查询元素是否存在

使用 contains 方法来检查元素是否存在于 TreeSet 中:

boolean containsC = treeSet.contains("C");

5. 遍历 TreeSet

遍历 TreeSet 中的元素通常使用迭代器或增强的 for 循环。以下是两种遍历方式的示例:

5.1. 使用迭代器遍历

Iterator<String> iterator = treeSet.iterator();
while (iterator.hasNext()) {
    String element = iterator.next();
    System.out.println(element);
}

5.2. 使用增强的 for 循环遍历

for (String element : treeSet) {
    System.out.println(element);
}

无论哪种方式,遍历 TreeSet 都会按照元素的顺序输出元素值。

6. 示例:使用 TreeSet

让我们通过一些示例代码来演示 TreeSet 的使用场景:

6.1. 存储成绩

假设我们要存储一组学生的成绩,并且希望按照成绩从低到高的顺序排列。我们可以使用 TreeSet 来实现:

TreeSet<Integer> studentScores = new TreeSet<>();

studentScores.add(85);
studentScores.add(92);
studentScores.add(78);
studentScores.add(92); // 这个重复的成绩将被忽略

for (int score : studentScores) {
    System.out.println("成绩:" + score);
}

输出:

成绩:78
成绩:85
成绩:92

6.2. 记录考试排名

假设我们要记录一场考试的排名,并希望排名按照分数从高到低的顺序排列。我们可以使用 TreeSet 来存储排名信息:

TreeSet<Ranking> examRankings = new TreeSet<>(Comparator.reverseOrder());

examRankings.add(new Ranking("Alice", 95));
examRankings.add(new Ranking("Bob", 88));
examRankings.add(new Ranking("Charlie", 92));

for (Ranking ranking : examRankings) {
    System.out.println("排名:" + ranking.getName() + ",分数:" + ranking.getScore());
}

输出:

排名:Alice,分数:95
排名:Charlie,分数:92
排名:Bob,分数:88

7. TreeSet 的更多用法

当使用 TreeSet 时,除了基本的添加、删除、查询和遍历操作,还可以利用其更多的特性和方法来满足不同的需求。接下来,我们将介绍一些 TreeSet 的更多用法。

7.1. 获取第一个和最后一个元素

如果您需要获取 TreeSet 中的最小元素(第一个元素)或最大元素(最后一个元素),可以使用以下方法:

String firstElement = treeSet.first(); // 获取第一个元素
String lastElement = treeSet.last(); // 获取最后一个元素

这些方法在需要找到极值元素时非常有用。

7.2. 获取小于或大于某个元素的子集

TreeSet 提供了 headSettailSet 方法,用于获取小于或大于某个元素的子集。这在需要根据某个元素的值来划分集合时非常有用。

TreeSet<Integer> numbers = new TreeSet<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9));

// 获取小于等于 5 的子集
SortedSet<Integer> lessThanOrEqualFive = numbers.headSet(5); // [1, 2, 3, 4, 5]

// 获取大于等于 5 的子集
SortedSet<Integer> greaterThanOrEqualFive = numbers.tailSet(5); // [5, 6, 7, 8, 9]

7.3. 获取某一范围内的子集

除了获取小于或大于某个元素的子集,还可以获取某一范围内的子集,使用 subSet 方法:

// 获取范围在 [3, 7) 之间的子集(不包含 7)
SortedSet<Integer> subset = numbers.subSet(3, 7); // [3, 4, 5, 6]

7.4. 寻找最接近的元素

TreeSet 提供了 ceilingfloor 方法,用于寻找最接近指定元素的元素。ceiling 方法返回大于等于指定元素的最小元素,而 floor 方法返回小于等于指定元素的最大元素。

TreeSet<Integer> numbers = new TreeSet<>(Arrays.asList(1, 3, 6, 8, 10));

int closestGreaterOrEqual = numbers.ceiling(5); // 返回 6
int closestLessOrEqual = numbers.floor(5); // 返回 3

7.5. 比较两个 TreeSet

如果您需要比较两个 TreeSet 是否相等或一个是否包含另一个,可以使用 equalscontainsAll 方法:

TreeSet<Integer> set1 = new TreeSet<>(Arrays.asList(1, 2, 3, 4, 5));
TreeSet<Integer> set2 = new TreeSet<>(Arrays.asList(3, 4, 5));

boolean areEqual = set1.equals(set2); // 判断两个集合是否相等
boolean containsAll = set1.containsAll(set2); // 判断 set1 是否包含 set2 的所有元素

7.6. 自定义比较器

默认情况下,TreeSet 使用元素的自然顺序来排序。但是,您也可以通过提供自定义比较器来指定排序规则。比较器必须实现 Comparator 接口。

// 使用自定义比较器来按字符串长度排序
TreeSet<String> customOrderSet = new TreeSet<>(Comparator.comparing(String::length));

customOrderSet.add("apple");
customOrderSet.add("banana");
customOrderSet.add("cherry");

// 结果:[apple, cherry, banana]

以上是 TreeSet 的一些更多用法,根据您的需求,您可以灵活运用这些方法来处理和操作有序集合中的数据。请根据具体场景选择适当的方法和特性,以便更高效地使用 TreeSet

8. TreeSet 使用注意事项

在使用 TreeSet 时,有一些注意事项需要考虑,以确保正确、高效地使用该集合。

8.1. 唯一性

TreeSet 是一个有序的集合,它确保了元素的唯一性。这意味着集合中不会包含重复的元素。如果您尝试将重复元素添加到 TreeSet 中,它们将被忽略。因此,如果您需要处理重复元素,可能需要考虑其他集合类型,如 ArrayListLinkedList

8.2. 自然顺序

TreeSet 默认按照元素的自然顺序进行排序。如果元素类型实现了 Comparable 接口,它将使用 compareTo 方法来确定元素之间的顺序。如果元素类型没有实现 Comparable 接口,并且没有提供自定义的比较器,添加元素时可能会引发 ClassCastException

8.3. 自定义比较器

如果需要根据不同的排序规则来处理元素,可以提供自定义的比较器。自定义比较器必须实现 Comparator 接口,并在创建 TreeSet 时传递给构造函数。这样,您可以控制元素的排序方式,而不仅仅依赖于自然顺序。

8.4. 性能考虑

TreeSet 的插入、删除和查询操作的平均时间复杂度为 O(log n),其中 n 是集合中的元素数量。这意味着 TreeSet 对于大型数据集合是高效的。然而,在某些情况下,其他数据结构,如 HashSet,可能会更快,因为它们的性能更接近于 O(1)。

8.5. 并发性

TreeSet 不是线程安全的,如果多个线程同时访问和修改同一个 TreeSet 实例,可能会导致不一致的结果或并发问题。如果需要在多线程环境中使用 TreeSet,请考虑使用 Collections.synchronizedSortedSet 来创建一个线程安全的集合。

8.6. 遍历顺序

TreeSet 的元素是按照排序顺序存储的。因此,通过迭代器或增强的 for 循环遍历时,元素的顺序是有序的。这可以用于按顺序访问元素,但请注意,这可能与元素插入的顺序不同。

8.7. 空集合

TreeSet 可以包含空元素(null),但请小心使用。如果您要在集合中包含 null 元素,请确保您的比较器或元素类型不会导致意外的行为。

总之,TreeSet 是一个强大的有序集合,但在使用时需要注意其唯一性、排序方式、性能、并发性等方面的问题。根据具体需求选择合适的集合类型,并确保正确处理和操作数据以避免潜在的问题。

9. 总结

在本篇博客中,我们深入探讨了 TreeSet,这是 Java 集合框架中的一种有序集合。我们了解了它的概念、特性、内部实现、创建与初始化方法以及基本操作。通过示例代码,我们演示了如何使用 TreeSet 来解决不同场景的问题,如存储成绩和记录考试排名。希望本文能帮助您更好地理解和应用 TreeSet,并在实际开发中充分利用它的有序性和唯一性特点。如果您有任何问题或建议,请随时提出,我们将竭诚为您提供帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1005824.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++技能树】手撕AVL树 --插入与旋转详解

Halo&#xff0c;这里是Ppeua。平时主要更新C&#xff0c;数据结构算法&#xff0c;Linux与ROS…感兴趣就关注我bua&#xff01; 文章目录 0.平衡搜索二叉树概念0.1 平衡因子 1.插入1.1 普通插入操作1.2更新平衡因子 2.旋转2.1 左单旋2.2 右单旋2.3 右左双旋2.4 左右双旋 3. 旋…

量化:Fama-French五因子模型复现

文章目录 参考三因子模型概述策略设计 五因子模型概述 参考 掘金-fama三因子 b站-fama三因子 知乎-fama五因子 因子溢价、因子暴露及用途 三因子模型 概述 在CAPM模型的基础上加入了两个因子提出了三因子模型&#xff0c;三因子分别为 市场因子MKT规模因子SMB&#xff08;S…

收货已完成,删除采购订单没有任何提示

收货已完成或发票已校验&#xff0c;此时删除订单系统是不允许的&#xff0c;正常会报错06115&#xff0c; 现在问题是生产机不报这个消息&#xff0c;直接删除了订单行&#xff0c;查了一下资料&#xff0c;都说这个配置是系统写死的&#xff0c;通过增加06115的消息号 也不起…

算法:经典贪心算法--跳一跳[2]

1、题目&#xff1a; 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 返回到达 nums[n - 1] 的最小跳跃次数。生…

Maven 安装配置

Maven 安装配置 文章目录 Maven 安装配置一、下载 Maven二、解压Maven核心程序三、指定本地仓库四、配置阿里云镜像仓库4.1 将原有的例子配置注释掉4.2 加入新的配置 五、配置 Maven 工程的基础 JDK 版本六、配置环境变量6.1 检查 JAVAHOME 配置是否正确6.2 配置 MAVENHOME6.3 …

一个综合资产收集和漏洞扫描工具

Komo 介绍 Komo是一个综合资产收集和漏洞扫描工具&#xff0c;并且支持进度记录&#xff0c;通过多种方式对子域进行获取&#xff0c;收集域名&#xff0c;邮箱&#xff0c;子域名存活探测&#xff0c;域名指纹识别&#xff0c;域名反查ip&#xff0c;ip端口扫描&#xff0c;w…

Python 图形化界面基础篇:添加按钮( Button )到 Tkinter 窗口

Python 图形化界面基础篇&#xff1a;添加按钮&#xff08; Button &#xff09;到 Tkinter 窗口 引言什么是 Tkinter 按钮&#xff08; Button &#xff09;&#xff1f;步骤1&#xff1a;导入 Tkinter 模块步骤2&#xff1a;创建 Tkinter 窗口步骤3&#xff1a;创建按钮&…

2023年9月12日

实现一个图形类&#xff08;Shape&#xff09;&#xff0c;包含受保护成员属性&#xff1a;周长、面积&#xff0c; 公共成员函数&#xff1a;特殊成员函数书写 定义一个圆形类&#xff08;Circle&#xff09;&#xff0c;继承自图形类&#xff0c;包含私有属性&#xff1a;半…

【C++】STL之string

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言string类的内部成员变量&#xff1a; string的模拟实现**六个默认成员函数****iterator****capacity****modify**element access**String operations**Non-memb…

分布式id的概述与实现

文章目录 前言一、分布式id技术选型二、雪花算法三、在项目中集成雪花算法 前言 随着业务的增长&#xff0c;数据表可能要占用很大的物理存储空间&#xff0c;为了解决该问题&#xff0c;后期使用数据库分片技术。将一个数据库进行拆分&#xff0c;通过数据库中间件连接。如果…

C语言顺序表

文章目录 前言线性表顺序表静态顺序表动态顺序表 接口实现 前言 我们先补一下上篇博客落下的知识点&#xff1a; 首先说一下斐波那契的时间复杂度和空间复杂度&#xff1a; long long Fac(size_t N) {if(0 N)return 1;return Fac(N-1)*N; }还是说一下size_t代表的类型是unsi…

C#,数值计算——伽马微分(Gammadev)的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { public class Gammadev : Normaldev { private double alph { get; set; } private double oalph { get; set; } private double bet { get; set; } private double a1 { g…

2023年第十届中文自修杯汉字小达人比赛安排、常见问题和试卷题型

好消息&#xff01;面向上海市小学生的2023年第十届中文自修杯汉字小达人比赛开始了&#xff01; 这个活动从2014年开始举办第一届&#xff0c;迄今已经举办了九届&#xff0c;活动的影响力越来越大&#xff0c;深受上海市的小学生们欢迎。而且&#xff0c;有一些外省市的学校…

软件测评报告需要提交什么材料?

软件测评报告 软件测评/软件测试的经典定义是在规定条件下对程序进行操作&#xff0c;以发现错误&#xff0c;对软件质量进行评估。因为软件是由文档、数据以及程序组成的&#xff0c;所以软件测试的对象也就不仅仅是程序本身&#xff0c;而是包括软件形成过程的文档、数据以及…

Liunx系统下载安装Nginx下载安装

目录 版本介绍 Liunx下安装步骤 补充&#xff1a;Docker安装nginx 版本介绍 Nginx开源版 http://nginx.org/en/ 官方原始的Nginx版本 Nginx plus商业版 开箱即用&#xff0c;集成了大量功能 Open Resty https://openresty.org/cn/ OpenResty是一个基于Nginx与 Lua 的高性…

ModuleNotFoundError: No module named ‘transformers.modeling_bert‘解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

【LeetCode题目详解】第九章 动态规划part17 647. 回文子串 ● 516.最长回文子序列(day57补)

本文章代码以c为例&#xff01; 一、力扣第647题&#xff1a;回文子串 题目&#xff1a; 给你一个字符串 s &#xff0c;请你统计并返回这个字符串中 回文子串 的数目。 回文字符串 是正着读和倒过来读一样的字符串。 子字符串 是字符串中的由连续字符组成的一个序列。 具…

html5学习笔记21-css简略学习

CSS https://www.runoob.com/css/css-tutorial.html CSS (Cascading Style Sheets&#xff0c;层叠样式表&#xff09;&#xff0c;是一种用来为结构化文档&#xff08;如 HTML 文档或 XML 应用&#xff09;添加样式&#xff08;字体、间距和颜色等&#xff09;的计算机语言&a…

Ngnix封禁IP与ip段

Ngnix IP封禁以及实现自动封禁IP 小白教程&#xff0c;一看就会&#xff0c;一做就成。 1.创建文件&#xff08;被封禁的ip写里面&#xff09; 在ngnix的conf目录下创建一个blockip.conf文件&#xff0c;里面放需要封禁的IP与ip段&#xff0c;格式如下&#xff08;deny是禁用…

C++ 将off格式文件转换成ply格式存储

文章目录 引言off格式文件ply格式文件C标准库实现off转ply 引言 三维模型是计算机图形学中的一个重要概念&#xff0c;它是由一系列三维坐标点构成的点云或多边形网格。 OFF格式是一种用于描述三维模型的文件格式&#xff0c;它可以描述点云和多边形网格等不同类型的三维模型。…