子集算法的一个简单实现

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

于是自己想了一个思路:把关系表达式看做是区间,比如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( - 5 false ), Right  =   new  Endpoint( - 2 true ) });
 7              a.Add( new  Segment { Left  =   new  Endpoint( 1 false ), Right  =   new  Endpoint( 6 true ) });
 8 
 9              Set b  =   new  Set();
10              b.Add( new  Segment { Left  =   new  Endpoint( - 3 false ), Right  =   new  Endpoint( 0 true ) });
11              b.Add( new  Segment { Left  =   new  Endpoint( 4 false ), Right  =   new  Endpoint( 6 true ) });
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

 

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

 

转载于:https://www.cnblogs.com/rufi/archive/2010/05/21/SubSetProblem.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值