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));  
    }
}
相关推荐
谢亮_vipxieliang17 天前
ValidX vs Google Guava Preconditions:验证 vs 断言
java·spring boot·后端·spring cloud·hibernate·guava
吴声子夜歌20 天前
Guava——散列
java·guava
吴声子夜歌20 天前
Guava——并发(二)
java·网络·guava
吴声子夜歌20 天前
Guava——事件总线
java·网络·guava
吴声子夜歌20 天前
Guava——并发(一)
java·guava
吴声子夜歌20 天前
Guava——反射
java·开发语言·guava
吴声子夜歌20 天前
Guava——基本工具(二)
windows·python·guava
吴声子夜歌21 天前
Guava——基本工具(一)
windows·guava
吴声子夜歌21 天前
Guava——集合(二)
java·guava
吴声子夜歌21 天前
Guava——缓存
缓存·guava