提升编程效率的利器: 解析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,一经查实,立即删除!

相关文章

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

文章目录 传输介质及分类导向传输介质-双绞线导向传输介质-同轴电缆导向传输介质-光纤非导向性传输介质小结 传输介质及分类 物理层规定电气特性&#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中修…

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

弹性光顺法的基本特点 弹性光顺法中&#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、基本语法 ①初始…

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();限制省略函数返回类…

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

在油类化工厂、输油管道、油库等工业生产场所&#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…

【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、…

如何使用 Maltego 情报调查保姆级教程(附链接)

前言 使用软件需要挂梯子 一、介绍 Maltego 是一种开放源代码的情报和数据连接工具&#xff0c;专注于网络情报收集和图形化分析。它为用户提供了一个交互式的界面&#xff0c;用于收集、分析和可视化有关目标的信息。Maltego 被广泛用于网络侦查、威胁情报、渗透测试和安全…

Windows、Linux、Mac数据库的安装(mysql、MongoDB、Redis)

数据库的安装 作为数据存储的重要部分&#xff0c;数据库同样是必不可少的&#xff0c;数据库可以分为关系型数据库和非关系型数据库。 关系型数据库如 SQLite、MySQL、Oracle、SQL Server、DB2 等&#xff0c;其数据库是以表的形式存储&#xff1b;非关系型数据库如 MongoDB…

我用Rust开发Rocketmq name server

我是蚂蚁背大象(Apache EventMesh PMC&Committer)&#xff0c;文章对你有帮助给Rocketmq-rust star,关注我GitHub:mxsm&#xff0c;文章有不正确的地方请您斧正,创建ISSUE提交PR~谢谢! Emal:mxsmapache.com 1. Rocketmq-rust namesrv概述 经过一个多月的开发&#xff0c;终…

【web安全】文件上传漏洞

upload-labs靶场 第一关 绕过前端 先打开哥斯拉&#xff0c;生成木马&#xff0c;选择php 打开brup开浏览器&#xff0c;上传文件&#xff0c;就会发现被阻止了&#xff0c;还没抓到包呢 那就是被前端代码阻止了&#xff0c;那通常前端代码都只能防御后缀名 我们抓到包后直…

php+Layui开发的网站信息探针查询源码

信息探针是一款基于layui开发的专业查询好友个人信息的程序。 自定义设置探针页面&#xff0c;探针功能&#xff0c;QQ分享&#xff0c;通知邮箱等功能。 生成页面链接好友点击会出现好友ip 位置信息&#xff0c;手机型号ua头浏览器等信息 gps需要注册百度地图开发者才可以使用…

盒子模型的内容总结

知识引入 1.认识盒子模型 在浏览网站时我们会发现内容都是按照区域划分的。这使得网页很工整、美观。在页面中&#xff0c;每一块区域分别承载不同的内容&#xff0c;使得网页的内容虽然零散&#xff0c;但是在版式排列上依然清晰有条理。如图1 图1 *承载内容的区域称为盒子…

数字护盾:深度探讨Sentinel的三大流控策略

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 数字护盾&#xff1a;深度探讨Sentinel的三大流控策略 前言快速失败策略&#xff1a;数字守卫的拦截术快速失败策略的基本原理&#xff1a;示例场景演示&#xff1a; Warm Up策略&#xff1a;数字城堡…

如何安装配置HFS并实现无公网ip远程访问本地电脑共享文件

文章目录 前言1.下载安装cpolar1.1 设置HFS访客1.2 虚拟文件系统 2. 使用cpolar建立一条内网穿透数据隧道2.1 保留隧道2.2 隧道名称2.3 成功使用cpolar创建二级子域名访问本地hfs 总结 前言 在大厂的云存储产品热度下降后&#xff0c;私人的NAS热度快速上升&#xff0c;其中最…