• 子集算法的一个简单实现


    看了《子集算法的完整数学推导过程》这篇文章后,感觉里面的数学公式很多,较难转换成计算机程序。

    于是自己想了一个思路:把关系表达式看做是区间,比如3<x<=5是(3,5],逻辑与或运算就是区间的交集和并集运算。

    然后写程序实现了区间的子集,交集和并集运算。区间(Segment)有两个端点(Endpoit),难点是多个区间的集会(Set)之间的运算。

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 
      6 namespace SubSetProblem
      7 {
      8     public struct Endpoint
      9     {
     10         public double Value;
     11         public bool Inclusive;
     12 
     13         public Endpoint(double value, bool inclusive)
     14         {
     15             Value = value;
     16             Inclusive = inclusive;
     17         }
     18 
     19         public static bool operator <=(Endpoint a, Endpoint b)
     20         {
     21             return a.Value < b.Value ||
     22                 (a.Value == b.Value &&
     23                 !(a.Inclusive == true && b.Inclusive == false)
     24                 );
     25         }
     26 
     27         public static bool operator >=(Endpoint a, Endpoint b)
     28         {
     29             return a.Value > b.Value ||
     30                 (a.Value == b.Value &&
     31                 !(a.Inclusive == false && b.Inclusive == true)
     32                 );
     33         }
     34 
     35         public static bool operator <(Endpoint a, Endpoint b)
     36         {
     37             return !(a >= b);
     38         }
     39 
     40         public static bool operator >(Endpoint a, Endpoint b)
     41         {
     42             return !(a <= b);
     43         }
     44     }
     45 
     46     public struct Segment
     47     {
     48         public Endpoint Left;
     49         public Endpoint Right;
     50 
     51         public static readonly Segment Empty = new Segment();
     52 
     53         public override string ToString()
     54         {
     55             return String.Format(
     56                 "{0}{1}, {2}{3}", Left.Inclusive ? '[' : '(', Left.Value, Right.Value, Right.Inclusive ? ']' : ')');
     57         }
     58     }
     59 
     60     public class Set : List<Segment>
     61     {
     62         public new void Add(Segment seg)
     63         {
     64             if (seg.Equals(Segment.Empty) == false)
     65             {
     66                 base.Add(seg);
     67             }
     68         }
     69 
     70         public override string ToString()
     71         {
     72             StringBuilder text = new StringBuilder();
     73             text.Append('{');
     74             this.ForEach(s => { text.Append(s.ToString()); text.Append(""); });
     75             if (this.Count > 0)
     76             {
     77                 text.Length -= 2;
     78             }
     79             text.Append('}');
     80             return text.ToString();
     81         }
     82     }
     83 
     84     public class SetOperation
     85     {
     86         public static bool IsSubSet(Set a, Set b)
     87         {
     88             return a.Count(s => IsSubSet(s, b)) == a.Count;
     89         }
     90 
     91         public static bool IsSubSet(Segment seg, Set set)
     92         {
     93             return set.Count(s => IsSubSet(seg, s)) > 0;
     94         }
     95 
     96         public static bool IsSubSet(Segment a, Segment b)
     97         {
     98             return a.Left >= b.Left && a.Right <= b.Right;
     99         }
    100 
    101         public static Set Union(Set a, Set b)
    102         {
    103             Set union = b;
    104             foreach (var segA in a)
    105             {
    106                 union = Union(segA, union);
    107             }
    108             return union;
    109         }
    110 
    111         public static Set Intersect(Set a, Set b)
    112         {
    113             Set intersect = new Set();
    114             foreach (var segA in a)
    115             {
    116                 intersect = Union(intersect, Intersect(segA, b));
    117             }
    118             return intersect;
    119         }
    120 
    121         public static Set Union(Segment a, Set setB)
    122         {
    123             Set union = new Set();
    124             foreach (var b in setB)
    125             {
    126                 if (Intersect(a, b).Equals(Segment.Empty))
    127                 {
    128                     union.Add(b);
    129                 }
    130                 else
    131                 {
    132                     a = new Segment { Left = Min(a.Left, b.Left), Right = Max(a.Right, b.Right) };
    133                 }
    134             }
    135             union.Add(a);
    136             return union;
    137         }
    138 
    139         public static Set Intersect(Segment segA, Set b)
    140         {
    141             Set intersect = new Set();
    142             foreach (var segB in b)
    143             {
    144                 intersect = Union(Intersect(segA, segB), intersect);
    145             }
    146             return intersect;
    147         }
    148 
    149         public static Segment Intersect(Segment a, Segment b)
    150         {
    151             if (a.Equals(Segment.Empty) || b.Equals(Segment.Empty))
    152             {
    153                 return Segment.Empty;
    154             }
    155 
    156             var left = Max(a.Left, b.Left);
    157             var right = Min(a.Right, b.Right);
    158 
    159             if (left <= right)
    160             {
    161                 return new Segment { Left = left, Right = right };
    162             }
    163             else
    164             {
    165                 return Segment.Empty;
    166             }
    167         }
    168 
    169         public static Set Union(Segment a, Segment b)
    170         {
    171             var left = Max(a.Left, b.Left);
    172             var right = Min(a.Right, b.Right);
    173 
    174             Set union = new Set();
    175             if (left <= right)
    176             {
    177                 union.Add(new Segment { Left = Min(a.Left, b.Left), Right = Max(a.Right, b.Right) });
    178             }
    179             else
    180             {
    181                 union.Add(a);
    182                 union.Add(b);
    183             }
    184             return union;
    185         }
    186 
    187         public static Endpoint Min(Endpoint a, Endpoint b)
    188         {
    189             return a < b ? a : b;
    190         }
    191 
    192         public static Endpoint Max(Endpoint a, Endpoint b)
    193         {
    194             return a < b ? b : a;
    195         }
    196     }
    197 }

    比较复杂的是Set Union(Set a, Set b)和Set Intersect(Set a, Set b)这两个方法,请大家验证有无错误。

    接下来做了一个简单的测试:

     1     public class Test
     2     {
     3         public static string Test1()
     4         {
     5             Set a = new Set();
     6             a.Add(new Segment { Left = new Endpoint(-5false), Right = new Endpoint(-2true) });
     7             a.Add(new Segment { Left = new Endpoint(1false), Right = new Endpoint(6true) });
     8 
     9             Set b = new Set();
    10             b.Add(new Segment { Left = new Endpoint(-3false), Right = new Endpoint(0true) });
    11             b.Add(new Segment { Left = new Endpoint(4false), Right = new Endpoint(6true) });
    12 
    13             Set u = SetOperation.Union(a, b);
    14             Set i = SetOperation.Intersect(a, b);
    15 
    16             return u + " " + i + " " + SetOperation.IsSubSet(i, u);
    17         }
    18     }

    返回结果是:{(-5, 0], (1, 6]} {(4, 6], (-3, -2]} True

    以上代码只是对一维的区间的实现,也就是关系表达式里只有一个变量的情况。如果有多个维度,在现在的基础上做一些扩展也能实现。

  • 相关阅读:
    创建文件夹 文件File操作方法
    C#WinForm4张纸牌窗体设计
    b/s结构和c/s结构
    sql 中 时间只显示日期
    视图
    js获取字符串的字节数
    触发器
    将xml字符串转换成dataset
    sql 集合查询 数据更新操作语句
    带有ANY(SOME)或ALL谓词的字查询
  • 原文地址:https://www.cnblogs.com/rufi/p/SubSetProblem.html
Copyright © 2020-2023  润新知