Guava TreeRangeSet:区间运算的数学之美!

一、什么是TreeRangeSet?

TreeRangeSet是Guava中基于红黑树实现的区间集合。它专门用于处理区间的并集、交集、补集等数学运算,让复杂的区间逻辑变得简单直观。简单说,它就像是给区间运算装上了"数学大脑"!

二、为什么需要TreeRangeSet?

先来看个震撼对比:
传统区间判断:

java 复制代码
// 判断时间是否在多个允许区间内
List<TimeRange> allowedRanges = Arrays.asList(    
	new TimeRange("09:00", "12:00"),    
	new TimeRange("14:00", "18:00"));
public boolean isAllowed(LocalTime time) {   
	for (TimeRange range : allowedRanges) {        
		if (range.contains(time)) {            
			return true;        
			}    
		}    
		return false; // O(n)时间复杂度,还要处理区间重叠!
}

使用TreeRangeSet:

java 复制代码
RangeSet<LocalTime> allowedTimes = TreeRangeSet.create();
allowedTimes.add(Range.closedOpen(
	LocalTime.of(9, 0), LocalTime.of(12, 0)));
allowedTimes.add(Range.closedOpen(    
	LocalTime.of(14, 0), LocalTime.of(18, 0)));

// 一行代码搞定!
boolean allowed = allowedTimes.contains(LocalTime.of(10, 30)); // true
// 自动处理区间合并:[9:00-12:00] ∪ [14:00-18:00]

数学般的优雅,这才是编程的艺术!

三、TreeRangeSet的核心设计思想

  1. 区间代数的编程实现
  1. 规范化的区间存储

  2. 基于红黑树的高效运算

四、TreeRangeSet的核心API详解

  1. 创建和基础操作

    创建TreeRangeSet

    添加和移除区间

  2. 查询操作

    点查询

    区间关系查询

  3. 集合运算

    补集运算

    子范围视图

    区间视图操作

五、实际开发中的使用场景

场景一:数学区间运算引擎

java 复制代码
/** * 数学区间运算引擎 - 使用TreeRangeSet实现复杂区间计算 */
public  class  MathIntervalEngine 
{   
    private  final RangeSet < Double > domain;   
    private  final Map < String, RangeSet < Double >> namedSets;   
    public  MathIntervalEngine() 
    {     
        this.domain = TreeRangeSet.create();     
        this.namedSets =  new  HashMap < > ();      
      	// 默认定义实数域        
        domain.add(Range.all());  
    }    

	/**     * 定义命名的区间集合     */    
    public  void  defineSet(String name, RangeSet < Double >  set) 
    {    
        namedSets.put(name,  set);  
    }    
	/**     * 执行集合运算     */    
    public  RangeSet < Double >  evaluateExpression(String expression) 
    {      
      	// 简单的表达式解析器(实际应用可以使用更复杂的解析器)        
        if (expression.contains("∪"))
        {      
            String[] parts = expression.split("∪");       
            return  union(evaluateExpression(parts[0].trim()),              evaluateExpression(parts[1].trim()));    
        } 
        else  if (expression.contains("∩"))
        {      
            String[] parts = expression.split("∩");       
            return  intersection(evaluateExpression(parts[0].trim()),                 evaluateExpression(parts[1].trim()));    
        } 
        else  if (expression.contains("\\"))
        {      
            String[] parts = expression.split("\\\\");       
            return  difference(evaluateExpression(parts[0].trim()),                evaluateExpression(parts[1].trim()));    
        } 
        else  if (expression.startsWith("!"))
        {       
            return  complement(evaluateExpression(expression.substring(1).trim()));    
        } 
        else  if (namedSets.containsKey(expression))
        {       
            return  namedSets.get(expression);    
        } 
        else 
        {       
            return  parseRange(expression);    
        }  
    }    

	/**     * 并集运算     */    
    public  RangeSet < Double >  union(RangeSet < Double > set1, RangeSet < Double > set2) 
    {    
        RangeSet < Double > result = TreeRangeSet.create(set1);    
        result.addAll(set2);     
        return  result;  
    }    
	/**     * 交集运算     */    
    public  RangeSet < Double >  intersection(RangeSet < Double > set1, RangeSet < Double > set2) 
    {    
        RangeSet < Double > result = TreeRangeSet.create(set1);    
        result.removeAll(set2.complement());     
        return  result;  
    }    
	/**     * 差集运算     */    
    public  RangeSet < Double >  difference(RangeSet < Double > set1, RangeSet < Double > set2) 
    {    
        RangeSet < Double > result = TreeRangeSet.create(set1);    
        result.removeAll(set2);     
        return  result;  
    }    
	/**     * 补集运算     */    
    public  RangeSet < Double >  complement(RangeSet < Double >  set) 
    {     
        return  set.complement();  
    }    
	/**     * 解析区间表达式     */    
    private  RangeSet < Double >  parseRange(String expression) 
    {     
        try 
        {       
            if (expression.equals("R"))
            {        
                RangeSet < Double > realNumbers = TreeRangeSet.create();        
                realNumbers.add(Range.all());         
                return  realNumbers;      
            }        
          	// 解析类似 "[1, 5]"  "(2, 8)" 的表达式            
            expression = expression.trim();       
            char  leftBracket = expression.charAt(0);       
            char  rightBracket = expression.charAt(expression.length() -  1);      
            String[] parts = expression.substring(1, expression.length() -  1).split(",");       
            double  lower = Double.parseDouble(parts[0].trim());       
            double  upper = Double.parseDouble(parts[1].trim());      
            Range < Double > range;       
            if (leftBracket ==  '['  && rightBracket ==  ']')
            {        
                range = Range.closed(lower, upper);      
            } 
            else  if (leftBracket ==  '('  && rightBracket ==  ')')
            {        
                range = Range.open(lower, upper);      
            } 
            else  if (leftBracket ==  '['  && rightBracket ==  ')')
            {        
                range = Range.closedOpen(lower, upper);      
            } 
            else  if (leftBracket ==  '('  && rightBracket ==  ']')
            {        
                range = Range.openClosed(lower, upper);      
            } 
            else 
            {         
                throw  new  IllegalArgumentException("无效的区间表达式: "  + expression);      
            }      
            RangeSet < Double > result = TreeRangeSet.create();      
            result.add(range);       
            return  result;    
        } 
        catch (Exception e)
        {       
            throw  new  IllegalArgumentException("无法解析区间表达式: "  + expression, e);    
        }  
    }    
	/**     * 计算区间的度量(长度)     */    
    public  double  measure(RangeSet < Double >  set) 
    {     
        return  set.asRanges().stream()      .mapToDouble(range - >
        {         
            if (!range.hasLowerBound() || !range.hasUpperBound())
            {           
                return  Double.POSITIVE_INFINITY;        
            }         
            return  range.upperEndpoint() - range.lowerEndpoint();      
        })      .sum();  
    }    
    	/**     * 检查集合关系     */    
    public  SetRelation  checkRelation(RangeSet < Double > set1, RangeSet < Double > set2) 
    {    
        boolean subset = set1.enclosesAll(set2);    
        boolean superset = set2.enclosesAll(set1);    
        boolean disjoint = !set1.intersects(set2);     
        if (subset && superset)
        {       
            return  SetRelation.EQUAL;    
        } 
        else  if (subset)
        {       
            return  SetRelation.SUBSET;    
        } 
        else  if (superset)
        {       
            return  SetRelation.SUPERSET;    
        } 
        else  if (disjoint)
        {       
            return  SetRelation.DISJOINT;    
        } 
        else 
        {       
            return  SetRelation.OVERLAP;    
        }  
    }    
	/**     * 求解不等式系统     */    
    public  RangeSet < Double >  solveInequalitySystem(List < String > inequalities) 
    {    
        RangeSet < Double > solution = TreeRangeSet.create();    
        solution.add(Range.all()); 
        // 初始化为全体实数
             
        for (String inequality: inequalities)
        {      
            RangeSet < Double > inequalitySet = parseInequality(inequality);      
            solution = intersection(solution, inequalitySet);    
        }     
        return  solution;  
    }   
    private  RangeSet < Double >  parseInequality(String inequality) 
    {    
        inequality = inequality.trim();    
        RangeSet < Double > result = TreeRangeSet.create();     
        if (inequality.contains(">="))
        {      
            String[] parts = inequality.split(">=");       
            double  value  = Double.parseDouble(parts[1].trim());      
            result.add(Range.atLeast(value));    
        } 
        else  if (inequality.contains("<="))
        {      
            String[] parts = inequality.split("<=");       
            double  value  = Double.parseDouble(parts[1].trim());      
            result.add(Range.atMost(value));    
        } 
        else  if (inequality.contains(">"))
        {      
            String[] parts = inequality.split(">");       
            double  value  = Double.parseDouble(parts[1].trim());      
            result.add(Range.greaterThan(value));    
        } 
        else  if (inequality.contains("<"))
        {      
            String[] parts = inequality.split("<");       
            double  value  = Double.parseDouble(parts[1].trim());      
            result.add(Range.lessThan(value));    
        } 
        else  if (inequality.contains("="))
        {      
            String[] parts = inequality.split("=");       
            double  value  = Double.parseDouble(parts[1].trim());      
            result.add(Range.singleton(value));    
        }     
        return  result;  
    }    

	/**     * 生成区间可视化描述     */    
    public  String  visualize(RangeSet < Double >  set,  double  from,  double  to,  int  width) 
        {    
            StringBuilder sb =  new  StringBuilder();    
            sb.append("数轴: ").append(from).append(" 到 ").append(to).append("\n");     
            double  step = (to -  from) / width;     
            for (int  i =  0; i <= width; i++)
            {       
                double  x =  from  + i * step;       
                if (set.contains(x))
                {        
                    sb.append("█");      
                } 
                else 
                {        
                    sb.append(" ");      
                }    
            }    
            sb.append("\n刻度: ");     
            for (int  i =  0; i <= width; i += width /  10)
            {       
                double  x =  from  + i * step;      
                sb.append(String.format("%.1f ", x));    
            }     
            return  sb.toString();  
        }    

	// 集合关系枚举    
    public  enum  SetRelation
    {    
        EQUAL, SUBSET, SUPERSET, DISJOINT, OVERLAP  
    }    

	/**     * 演示复杂的区间运算     */    
    public  void  demonstrateComplexOperations() 
    {      
      
      	// 定义几个集合        
        defineSet("A", parseRange("[0, 5]"));    
        defineSet("B", parseRange("[3, 8]"));    
        defineSet("C", parseRange("[1, 10]"));     
        // 执行复杂运算: (A ∪ B) ∩ !C        
        RangeSet < Double > result = evaluateExpression("(A ∪ B) ∩ !C");    
        System.out.println("A = "  + namedSets.get("A"));    
        System.out.println("B = "  + namedSets.get("B"));    
        System.out.println("C = "  + namedSets.get("C"));    
        System.out.println("(A ∪ B) ∩ !C = "  + result);    
        System.out.println("度量: "  + measure(result));      // 可视化结果        
        System.out.println(visualize(result,  -2,  12,  80));  
    }
}
相关推荐
信仰_27399324312 小时前
Guava Cache淘汰算法
算法·guava
我命由我123454 天前
Guava - Guava 基本工具 Preconditions、Optional
java·服务器·开发语言·后端·java-ee·guava·后端框架
Lisonseekpan1 个月前
Guava Cache 高性能本地缓存库详解与使用案例
java·spring boot·后端·缓存·guava
木易小熙1 个月前
Guava Cache
java·spring·guava
Full Stack Developme1 个月前
Java 工具类 Hutool、Guava 与 Apache Commons 的区别
java·apache·guava
Mr.45671 个月前
【干货分享】Guava LoadingCache 使用指南:打造高性能本地缓存
guava
sibylyue2 个月前
Guava中常用的工具类
java·guava
howeres3 个月前
Guava
guava
sqyaa.4 个月前
Guava LoadingCache
jvm·缓存·guava