提升编程效率的利器: 解析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来解决时间范围管理、数字范围限制等问题,提高代码的可读性和维护性。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一文掌握 Golang 加密:crypto/cipher 标准库全面指南

一文掌握 Golang 加密&#xff1a;crypto/cipher 标准库全面指南 引言Golang 和加密简介crypto/cipher 库概览使用 crypto/cipher 实现加密高级功能和技巧最佳实践和性能优化总结资源推荐 引言 在现代软件开发领域&#xff0c;安全性是一个不容忽视的重要议题。随着信息技术的…

黑盒测试用例的具体设计方法(7种)

7种常见的黑盒测设用例设计方法&#xff0c;分别是等价类、边界值、错误猜测法、场景设计法、因果图、判定表、正交排列。 &#xff08;一&#xff09;等价类 1.概念 依据需求将输入&#xff08;特殊情况下会考虑输出&#xff09;划分为若干个等价类&#xff0c;从等价类中选…

备战蓝桥杯---数据结构与STL应用(基础实战篇1)

话不多说&#xff0c;直接上题&#xff1a; 当然我们可以用队列&#xff0c;但是其插入复杂度为N,总的复杂度为n^2,肯定会超时&#xff0c;于是我们可以用链表来写&#xff0c;同时把其存在数组中&#xff0c;这样节点的访问复杂度也为o(1).下面是AC代码&#xff1a; 下面我们来…

Vim实战:使用Vim实现图像分类任务(一)

文章目录 摘要安装包安装timm 数据增强Cutout和MixupEMA项目结构编译安装Vim环境环境安装过程安装库文件 计算mean和std生成数据集 摘要 论文&#xff1a;https://arxiv.org/pdf/2401.09417v1.pdf 翻译&#xff1a; 近年来&#xff0c;随着深度学习的发展&#xff0c;视觉模型…

项目解决方案:高清视频监控联网设计方案

目 录 一、客户需求 二、网络拓扑图 三、方案描述 四、服务器配置 五、方案优势 1. 多级控制 2. 平台可堆叠使用 3. 支持主流接入协议 4. 多种终端显示 5. 视频质量诊断 6. 客户端功能强大 7. 一机一档 一、客户需求 客户现场存在两个网络环境&#xff0c…

25考研北大软微该怎么做?

25考研想准备北大软微&#xff0c;那肯定要认真准备了 考软微需要多少实力 现在的软微已经不是以前的软微了&#xff0c;基本上所有考计算机的同学都知道&#xff0c;已经没有什么信息优势了&#xff0c;只有实打实的有实力的选手才建议报考。 因为软微的专业课也是11408&am…

HarmonyOS4.0系统性深入开发31创建列表(List)

创建列表&#xff08;List&#xff09; 概述 列表是一种复杂的容器&#xff0c;当列表项达到一定数量&#xff0c;内容超过屏幕大小时&#xff0c;可以自动提供滚动功能。它适合用于呈现同类数据类型或数据类型集&#xff0c;例如图片和文本。在列表中显示数据集合是许多应用…

[DotNetGuide]C#/.NET/.NET Core优秀项目和框架精选

前言 注意&#xff1a;排名不分先后&#xff0c;都是十分优秀的开源项目和框架&#xff0c;每周定期更新分享&#xff08;欢迎关注公众号&#xff1a;追逐时光者&#xff0c;第一时间获取每周精选分享资讯&#x1f514;&#xff09;。 帮助开发者发现功能强大、性能优越、创新前…

R语言学习case7:ggplot基础画图(核密度图)

step1: 导入ggplot2库文件 library(ggplot2)step2&#xff1a;带入自带的iris数据集 iris <- datasets::irisstep3&#xff1a;查看数据信息 dim(iris)维度为 [150,5] head(iris)查看数据前6行的信息 step4&#xff1a;画图展示 plot2 <- ggplot(iris,aes(Sepal.W…

基于C#制作一个连连看小游戏

基于C#制作一个连连看小游戏,实现:难易度选择、关卡选择、倒计时进度条、得分计算、音效播放等功能。 目录 引言游戏规则开发环境准备游戏界面设计游戏逻辑实现图片加载与显示鼠标事件处理游戏优化与扩展添加关卡与难度选择说明</

wpf 数据转换(Bytes 转 KB MB GB)

效果 后端 using ProCleanTool.Model; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Data;namespace P…

Python(19)Excel表格操作Ⅰ

目录 导包 读取EXCEL文件 1、获取worksheet名称 2、设定当前工作表 3、输出目标单元格数据 4、工作表.rows&#xff08;行&#xff09; 5、工作表.columns&#xff08;列&#xff09; 小结 导包 要想使用 python 操作 Excel 文件&#xff0c;应当导入 openpyxl 包。在…

【Docker】WSL(Windows Subsystem for Linux)常见命令解释说明以及简单使用

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是《Docker容器》序列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对…

Flask 入门2

1. 在上一节中&#xff0c;我们使用到了静态路由&#xff0c;即一个路由规则对应一个 URL。而在实际应用中&#xff0c;更多使用的则是动态路由&#xff0c;它的 URL是可变的。 2. 定义一个很常见的路由地址 app.route(/user/<username>) def user(username):return U…

鸿蒙首批原生应用!无感验证已完美适配鸿蒙系统

顶象无感验证已成功适配鸿蒙系统&#xff0c;成为首批鸿蒙原生应用&#xff0c;助力鸿蒙生态的快速发展。 作为全场景分布式操作系统&#xff0c;鸿蒙系统旨在打破不同设备之间的界限&#xff0c;实现极速发现、极速连接、硬件互助、资源共享。迄今生态设备数已突破8亿台&…

【环境配置】安装了pytorch但是报错torch.cuda.is_availabel()=Flase

解决思路&#xff1a;import torch正常&#xff0c;说明torch包安装正常&#xff0c;但是不能和gpu正常互动&#xff0c;猜测还是pytroch和cuda的配合问题 1.查看torch包所需的cuda版本 我的torch是2.0.1&#xff0c;在现在是比较新的包&#xff0c;需要12以上的cuda支持&…

【flutter项目类型】project type如何区分

通过项目中.metadata内容区分 如 # Used by Flutter tool to assess capabilities and perform upgrades etc. # # This file should be version controlled and should not be manually edited.version:revision: 85684f9300908116a78138ea4c6036c35c9a1236channel: stablep…

vs 撤销本地 commit 并保留更改

没想到特别好的办法&#xff0c;我想的是用 vs 打开 git 命令行工具 然后通过 git 命令来撤销提交&#xff0c;尝试之前建议先建个分支实验&#xff0c;以免丢失代码&#xff0c; git 操作见 git 合并多个 commit / 修改上一次 commit

PaddleNLP的简单使用

1 介绍 PaddleNLP是一个基于PaddlePaddle深度学习平台的自然语言处理&#xff08;NLP&#xff09;工具库。 它提供了一系列用于文本处理、文本分类、情感分析、文本生成等任务的预训练模型、模型组件和工具函数。 PaddleNLP有统一的应用范式&#xff1a;通过 paddlenlp.Task…

单片机学习笔记---静态数码管显示

目录 数码管是什么&#xff1f; 一位数码管的引脚定义 四位一体的数码管引脚定义 数码管的原理图解析 数码管怎么显示数据&#xff1f;&#xff08;总结代码显示&#xff09; 今天开始学习数码管&#xff0c;它比LED和独立按键复杂一点 数码管是什么&#xff1f; LED数码…