提升编程效率的利器: 解析Google Guava库之集合篇RangeSet范围集合(五)

在编程中,我们经常需要处理各种范围集合,例如时间范围、数字范围等。传统的集合类库往往只能处理离散的元素集合,对于范围集合的处理则显得力不从心。为了解决这个问题,Google的Guava库提供了一种强大的数据结构——RangeSet,专门用于高效处理范围集合。

提升编程效率的利器: 解析Google Guava库之集合篇Immutable(一)
提升编程效率的利器: 解析Google Guava库之集合篇Multimap(二)
提升编程效率的利器: 解析Google Guava库之集合篇BitMap(三)
提升编程效率的利器: 解析Google Guava库之集合篇Table二维映射(四)

一、RangeSet简介

RangeSet是Guava库中的一个接口,它表示一组不重叠的、非空的范围集合。RangeSet中的每个范围都是一个Range对象,Range对象表示一个具有起始和结束边界的范围。RangeSet提供了一种方便的方式来管理和操作这些范围。

RangeSet还提供了丰富的查询和操作功能。例如,可以使用contains©方法查询给定的元素是否在RangeSet里,rangeContaining©方法返回包含给定元素的Range(如果不存在则返回null),以及encloses(Range)方法用来判断给定的Range是否包含在RangeSet里面。此外,span()方法返回一个包含在这个RangeSet的所有Range的并集。

要实现RangeSet接口,可以选择使用它的两个主要实现类:ImmutableRangeSet和TreeRangeSet。其中,ImmutableRangeSet是一个不可修改的RangeSet,而TreeRangeSet则是利用树的形式来实现,提供了高效的查询和插入操作。

二、RangeSet的核心特性

  • 自动合并范围:
    当向RangeSet中添加一个新的范围时,它会自动与现有的范围进行合并。如果新的范围与某个现有范围相交或相邻,它们会被合并成一个更大的范围。这种自动合并的特性使得RangeSet能够保持范围的不重叠性,从而简化了范围集合的管理。

  • 高效的查询操作:
    RangeSet提供了丰富的查询操作,可以快速地判断一个元素是否在某个范围内、获取包含某个元素的范围等。这些查询操作都是基于对范围树的高效遍历实现的,能够在对数时间内给出结果。

  • 灵活的范围操作:
    除了基本的查询操作外,RangeSet还支持各种范围操作,如并集、交集、差集等。这些操作可以方便地对范围集合进行组合和变换,满足各种复杂的需求。

三、RangeSet的实现原理

RangeSet的实现原理主要基于一种称为“范围树”的数据结构。范围树是一种平衡树,其中每个节点都表示一个范围。树中的节点按照范围的起始位置进行排序,以便快速查找和定位特定的范围。

当向RangeSet中添加一个新的范围时,它会遍历范围树,找到与新范围相交或相邻的现有范围,并进行合并。合并后的范围会被插入到树中的适当位置,以保持树的平衡性。这种合并和插入操作的时间复杂度都是对数级别的,因此RangeSet能够高效地处理大量的范围添加操作。

对于查询操作,RangeSet可以利用范围树的结构进行快速查找。例如,当查询一个元素是否包含在RangeSet中时,可以从树的根节点开始,沿着适当的分支向下遍历,直到找到一个包含该元素的范围或确定该元素不在RangeSet中。这种查询操作的时间复杂度也是对数级别的,因此RangeSet能够高效地处理大量的查询请求。

四、RangeSet的使用示例

使用 RangeSet 之前,我们得先了解一下 Guava 的Range 类,其实顾名思义就是表达区间范围,我们看一下它的 type 就明白了:
在这里插入图片描述

下面是一个使用RangeSet的简单示例,演示了如何创建一个RangeSet、向其中添加范围、并进行查询操作:

import com.google.common.collect.Range;  
import com.google.common.collect.RangeSet;  
import com.google.common.collect.TreeRangeSet;  public class TreeRangeSetDemo {  public static void main(String[] args) {  // 创建一个空的TreeRangeSet  RangeSet<Integer> rangeSet = TreeRangeSet.create();  // 向RangeSet中添加几个不连续的范围  rangeSet.add(Range.closed(1, 3));     // [1, 3]  rangeSet.add(Range.open(5, 8));       // (5, 8)  rangeSet.add(Range.closedOpen(10, 12));// [10, 12)  rangeSet.add(Range.greaterThan(15));   // (15, +∞)  // 打印当前RangeSet的内容  System.out.println(rangeSet); // [1..3](5..8)[10..12)(15..+∞)  // 查询某个范围是否包含在RangeSet中  System.out.println(rangeSet.contains(Range.closed(2, 3)));   // true  System.out.println(rangeSet.contains(Range.open(6, 7)));     // true  System.out.println(rangeSet.contains(Range.closed(11, 11))); // true  System.out.println(rangeSet.contains(Range.closed(4, 5)));   // false  // 删除一个范围  rangeSet.remove(Range.open(5, 8));  System.out.println(rangeSet); // [1..3][10..12)(15..+∞)  // 获取与指定范围重叠的范围  RangeSet<Integer> overlappingRanges = rangeSet.subRangeSet(Range.atLeast(9));  System.out.println(overlappingRanges); // [10..12)(15..+∞)  // 获取指定范围的补集(这里仅展示与[0, 20]范围内的补集)  RangeSet<Integer> complement = rangeSet.complement().subRangeSet(Range.closed(0, 20));  System.out.println(complement); // (0..1)(3..5)(8..10)[12..15][15..20]  // 注意:由于complement()返回的是整个数域中不属于rangeSet的部分,  // 我们再次使用subRangeSet来限制补集的范围,以便更好地展示结果。  // 查询单个元素是否在RangeSet中  System.out.println(rangeSet.contains(2));    // true  System.out.println(rangeSet.contains(9));    // false  // 获取包含指定元素的范围  Range<Integer> rangeContaining11 = rangeSet.rangeContaining(11);  System.out.println(rangeContaining11); // [10..12)  Range<Integer> rangeContaining4 = rangeSet.rangeContaining(4);  System.out.println(rangeContaining4); // null,因为4不在rangeSet中  // 获取RangeSet的最小和最大元素(注意这不是一个Range,而是两个元素)  Integer minValue = rangeSet.asRanges().stream().map(Range::lowerEndpoint).min(Integer::compareTo).orElse(null);  Integer maxValue = rangeSet.asRanges().stream().map(Range::upperEndpoint).max(Integer::compareTo).orElse(null);  System.out.println("Min value: " + minValue); // Min value: 1  System.out.println("Max value: " + maxValue); // Max value: 2147483647 (Integer.MAX_VALUE,因为rangeSet包含(15..+∞))  }  
}

在这个例子中,我添加了一些不连续的整数范围,并进行了基本的操作,包括添加、删除范围、查询范围是否存在、获取范围的补集以及与指定范围重叠的范围等。我也演示了如何获取RangeSet中的最小和最大元素,尽管对于无限范围(15…+∞),最大值实际上是Integer.MAX_VALUE,因为TreeRangeSet内部使用Integer来表示范围,并且它会将这个无限范围视为上界为Integer.MAX_VALUE的范围。

请注意,在实际应用中,处理无限范围时应该特别小心,因为整数是有界的,而TreeRangeSet的某些操作可能会受到这个限制的影响。

再来看下 循环遍历 和 使用encloses方法检查范围包含关系 的示例:

        // 创建一个TreeRangeSet并添加一些不连续的范围  TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();  rangeSet.add(Range.closed(1, 3));  rangeSet.add(Range.open(5, 8));  rangeSet.add(Range.closedOpen(10, 12));  rangeSet.add(Range.greaterThan(15));  // 使用encloses方法检查范围包含关系  boolean enclosesClosedRange = rangeSet.encloses(Range.closed(2, 3)); // true,因为[2,3]被[1,3]完全包含  boolean enclosesOpenRange = rangeSet.encloses(Range.open(6, 7)); // true,(6,7)被(5,8)完全包含  boolean enclosesSingletonRange = rangeSet.encloses(Range.singleton(11)); // true,11被[10,12)完全包含  boolean notEnclosesRange = rangeSet.encloses(Range.closed(4, 5)); // false,[4,5]不被任何范围完全包含  System.out.println("rangeSet.encloses(Range.closed(2, 3)): " + enclosesClosedRange);  System.out.println("rangeSet.encloses(Range.open(6, 7)): " + enclosesOpenRange);  System.out.println("rangeSet.encloses(Range.singleton(11)): " + enclosesSingletonRange);  System.out.println("rangeSet.encloses(Range.closed(4, 5)): " + notEnclosesRange);  // 遍历TreeRangeSet中的所有范围  System.out.println("Iterating over the ranges in the TreeRangeSet:");  Iterator<Range<Integer>> iterator = rangeSet.asRanges().iterator();  while (iterator.hasNext()) {  Range<Integer> range = iterator.next();  System.out.println(range);  }  // 使用增强的for循环遍历(更简洁)  System.out.println("Iterating over the ranges using enhanced for loop:");  for (Range<Integer> range : rangeSet.asRanges()) {  System.out.println(range);  }  }  

五、总结

Guava的RangeSet提供了一种高效、灵活的方式来处理范围集合。它基于范围树的数据结构,实现了范围的自动合并和高效的查询操作。通过RangeSet,我们可以方便地管理和操作各种范围集合,满足各种复杂的需求。在实际应用中,我们可以利用RangeSet来解决时间范围管理、数字范围限制等问题,提高代码的可读性和维护性。

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

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

相关文章

【Transformer 】 Hugging Face手册 (01/10)

一、说明 本文是Hugging Face的用户手册。加入 Hugging Face 社区&#xff0c;在模型、数据集和空间上进行协作&#xff0c;通过加速推理获得更快的示例。 二、变形金刚 适用于 PyTorch、TensorFlow 和 JAX 的先进机器学习。 Transformers 提供 API 和工具&#xff0c;可轻松下…

计算机网络-物理层传输介质(导向传输介质-双绞线 同轴电缆 光纤和非导向性传输介质-无线波 微波 红外线 激光)

文章目录 传输介质及分类导向传输介质-双绞线导向传输介质-同轴电缆导向传输介质-光纤非导向性传输介质小结 传输介质及分类 物理层规定电气特性&#xff1a;规定电气信号对应的数据 导向传输介质-双绞线 双绞线的主要作用是传输数据和语音信息。它通过将两根导线以特定的方…

C#,德兰诺依数(Dealnnoy Number)的算法与源代码

1 Dealnnoy Number 德兰诺依数&#xff0c;德兰诺伊数 德兰诺依数是以法国军官、业余数学家亨利德兰诺依&#xff08;Henry Dealnnoy&#xff09;的名字命名。 Henry Dealnnoy 在组合数学中&#xff0c;德兰诺依数描述了从(0,0)到(m,n)的格路问题中&#xff0c; 只允许按照(0…

vue3之echarts3D环柱饼图

vue3之echarts3D环柱饼图 效果&#xff1a; 版本 "echarts": "^5.4.1", "echarts-gl": "^2.0.9" 核心代码&#xff1a; <template><div class"content"><div ref"eCharts" class"chart&…

【uniapp·微信登录】

一、新建文件夹&#xff08;登录&#xff09; 在HBuilderX中开发微信小程序的步骤如下&#xff1a; 在HBuilderX中新建一个uniapp项目。 在HBuilderX中配置安装的微信开发者工具路径&#xff0c;可以通过点击 工具》设置》运行配置–小程序运行配置 进行配置。 在HBuilderX中修…

【MySQL】聚集函数注意事项

聚集函数注意事项 除了 COUNT(*) 不会忽略列值为 NULL 的行&#xff0c;其他的聚集函数都会忽略。 MAX() 也可以返回文本中的最大值&#xff0c;返回排序后的最后一行。 MIN() 也可以返回文本中的最小值&#xff0c;返回排序后的第一行。 使用标准的算术操作符&#xff08;加…

动网格-网格重构之弹性光顺局部重构法(四)

弹性光顺法的基本特点 弹性光顺法中&#xff0c;网格线类似于弹簧&#xff0c;两端节点(node)作弹性移动 弹性光顺法有如下特点。 (1)节点的数量和节点之间的连接关系均不变&#xff0c;即节点之间的连接属性不变。 (2)单独使用时&#xff0c;仅限于变形非常小的情况&#xff…

while 和 do-while

签名&#xff1a;但行好事&#xff0c;莫问前程。 文章目录 前言一、while1、基本语法2、执行过程3、示例 二、do-while1、基本语法2、执行过程3、小练习&#xff08;ATM存款取款机&#xff09; 总结 前言 记录一下while 和 do-while 的使用。 一、while 1、基本语法 ①初始…

【Java万花筒】Java引擎加速:GPU计算与并行处理库助力你的应用翱翔

加速未来&#xff1a;掌握GPU计算&#xff0c;助力Java应用飞跃 前言 随着计算需求的不断增加&#xff0c;GPU计算和并行处理技术成为提高应用程序性能的关键。在Java生态系统中&#xff0c;有许多强大的库和工具&#xff0c;可以帮助开发者充分利用GPU的并行计算能力&#x…

Navicat连接MySQL出现Host is not allowed to connect to this MySQL server 解决方法

翻译 &#xff1a;‘不允许主机连接到此MySQL服务器’ &#xff08;意思是本地账号连接可以登录&#xff0c;但是远程登陆不行&#xff09; 解决方案&#xff1a; 1、输入mysql账号密码&#xff0c;登录mysql mysql -uroot -p2、进入mysql库 use mysql; 3、修改root账号的host…

Java:SpringBoot整合Hashids,实现数据ID加密隐藏

引入依赖 <dependency><groupId>org.hashids</groupId><artifactId>hashids</artifactId><version>1.0.3</version> </dependency>步骤 1、自定义注解 Documented Retention(RetentionPolicy.RUNTIME) Target({ElementType…

OpenHarmony—ArkTS限制throw语句中表达式的类型

规则&#xff1a;arkts-limited-throw 级别&#xff1a;错误 ArkTS只支持抛出Error类或其派生类的实例。禁止抛出其他类型&#xff08;例如number或string&#xff09;的数据。 TypeScript throw 4; throw ; throw new Error();ArkTS throw new Error();限制省略函数返回类…

el-tree实现多选、反选、指定选择

最近项目中遇到实现设备多选的需求&#xff0c;虽然这个需求很常见&#xff0c;但功能需求的不同&#xff0c;实现过程也大相径庭&#xff0c;我们的需求时只提供子级选择&#xff0c;父级不做选择&#xff0c;只提供层级显示&#xff1b; el-tree是elementPlus的组件&#xf…

Codeforces Round 835 (Div. 4)

目录 A. Medium Number B. Atilla’s Favorite Problem C. Advantage D. Challenging Valleys E. Binary Inversions F. Quests G. SlavicG’s Favorite Problem A. Medium Number 中位数,排序之后处于中间位置的数 void solve() {n3;vector<int> a(n);for(auto&a…

漏油检测时间大幅缩短!漏油传感器的检测原理是什么?

在油类化工厂、输油管道、油库等工业生产场所&#xff0c;漏油情况时有发生&#xff0c;如果不能及时发现&#xff0c;往往产生非常严重的后果。因此&#xff0c;由漏油控制器和漏油检测绳组合而成的漏油传感器被广泛应用了起来&#xff0c;能够在发生漏油时及时发出告警&#…

AHK学习,诡异的早起,舒畅地打篮球——2024 第4周总结

活神仙 引言颓 周六周日理清当前老问题新问题 总结当前之前的老问题 学习的AHKAHK历程AHK作用和适合人群 我帮别人解决的AHK例子我自用的AKH功能结尾 引言 今天才写周总结 是因为这两天有点颓 颓在哪里呢&#xff1f; 请听我细细说来 水文 技术有 AHK的&#xff0c;不想看可以…

【React教程】(1) React简介、React核心概念、React初始化

目录 ReactReact 介绍React 特点React 的发展历史React 与 Vue 的对比技术层面开发团队社区Native APP 开发 相关资源链接 EcmaScript 6 补充React 核心概念组件化虚拟 DOM 起步初始化及安装依赖Hello World React React 介绍 React 是一个用于构建用户界面的渐进式 JavaScrip…

Java-12.Spring 中通过 ThreadPoolTaskExecutor 和 AsyncConfigurerSupport 配置默认异步线程池

Java-12a.Spring 中通过 TaskDecorator 配置默认异步线程池 前言 虽然在 SpringBoot 2.7.x 中已经有关于异步线程池的默认配置&#xff0c;但如果还是要自定义的需求&#xff0c;仍然值得学习了解一下。 例如&#xff1a;想要在多线程池中添加 traceId&#xff1b;使用 tran…

【DC-DC】AP5125 降压恒流驱动器 60W LED电源驱动方案PCB+BOM表

这是一款60WLED驱动方案,线路图如下 ​ 祥单表&#xff1a; 实物图&#xff1a; 产品描述 特点应用领域应用原理图AP5125 是一款外围电路简单的 Buck 型平均电流检测模式的 LED 恒流驱动器&#xff0c;适用于 8-100V 电压范围的非隔离式大功率恒流 LED 驱动领域。芯片采用固定…

APUE学习之进程间通信(IPC)(下篇)

目录 一、进程间通信&#xff08;IPC&#xff09; 二、信号量&#xff08;Semaphore&#xff09; 1、基本概念 2、同步关系与互斥关系 3、临界区与临界资源 4、信号量的工作原理 5、信号量编程 6、实战演练 三、共享内存&#xff08;Shared Memory&#xff09; 1、…