一些集合算法

转自http://bbs.csdn.net/topics/370006637

SetAlgorithm.cs

  1 using System;
  2 namespace Rabbit.Tools
  3 {
  4     public static class SetAlgorithms
  5     {
  6         /// <summary>
  7         /// 集合算法的回调
  8         /// </summary>
  9         /// <param name="result">运算结果</param>
 10         /// <param name="length">运算结果有效长度</param>
 11         /// <returns>控制算法是否继续,如果要结束算法,返回false</returns>
 12         /// <remarks>回调中不要修改result中的值,否则可能引起不可预知的后果</remarks>
 13         public delegate bool SetAlgorithmCallback (int[] result,int length);
 14 
 15         //argument check for arrangement and combination
 16         static bool CheckNM(int n, int m)
 17         {
 18             if (m > n || m < 0 || n < 0)
 19                 throw new ArgumentException();
 20 
 21             if (m == 0 || n == 0)
 22                 return false;
 23             return true;
 24         }
 25 
 26         static bool Arrangement(int n, int rlen, int[] result, SetAlgorithmCallback callback)
 27         {
 28             if (rlen == result.Length)
 29                 return callback(result, rlen);
 30 
 31             for (var i = 0; i < n; ++i)
 32             {
 33                 //skip used element
 34                 bool skip = false;
 35                 
 36                 for (var j = 0; j < rlen; ++j)
 37                 {
 38                     if (result[j] == i)
 39                     {
 40                         skip = true;
 41                         break;
 42                     }
 43                 }
 44 
 45                 if (skip)
 46                     continue;
 47                 //set element index
 48                 result[rlen] = i;
 49                 //recurrent next
 50                 if (!Arrangement(n, rlen + 1, result, callback))
 51                     return false;
 52             }
 53             return true;
 54         }
 55         /// <summary>
 56         /// 求排列A(n,m)
 57         /// </summary>
 58         /// <param name="n">集合元素个数</param>
 59         /// <param name="m">取出元素个数</param>
 60         /// <param name="callback">回调</param>
 61         public static void Arrangement(int n, int m, SetAlgorithmCallback callback)
 62         {
 63 
 64             if (!CheckNM(n, m))
 65                 return;
 66 
 67             var result = new int[m];
 68             for (var i = 0; i < n; ++i)
 69             {
 70                 result[0] = i;
 71                 if (!Arrangement(n, 1, result, callback))
 72                     return;
 73             }
 74         }
 75 
 76         static bool Combination(int n,int m, int i, int rlen, int[] result, SetAlgorithmCallback callback)
 77         {
 78             if (rlen == m)
 79                 return callback(result, rlen);
 80 
 81             for (var j = ++i; j < n; ++j)
 82             {
 83                 result[rlen] = j;
 84                 if (!Combination(n,m, j, rlen + 1, result, callback))
 85                     return false;
 86             }
 87             return true;
 88         }
 89         /// <summary>
 90         /// 求组合C(n,m)
 91         /// </summary>
 92         /// <param name="n">集合元素个数</param>
 93         /// <param name="m">取出元素个数</param>
 94         /// <param name="callback">回调</param>
 95         public static void Combination(int n, int m, SetAlgorithmCallback callback)
 96         {
 97             if (!CheckNM(n, m))
 98                 return;
 99 
100             int[] result;
101 
102             result = new int[n];
103             for (var i = 0; i < n; ++i)
104             {
105                 result[0] = i;
106 
107                 if (!Combination(n,m, i, 1, result,callback))
108                     return;
109             }
110         }
111 
112         static bool SubSet(int n, int i, int rlen, int[] result, SetAlgorithmCallback callback)
113         {
114             if (!callback(result, rlen))
115                 return false;
116 
117             if (rlen == n - 1)
118                 return true;
119 
120             for (var j = ++i; j < n; ++j)
121             {
122                 result[rlen] = j;
123                 if (!SubSet(n, j, rlen + 1, result, callback))
124                     return false;
125             }
126             return true;
127         }
128         /// <summary>
129         /// 求除空集外包含n个元素的集合的真子集
130         /// </summary>
131         /// <param name="n">集合元素个数</param>
132         public static void SubSet(int n, SetAlgorithmCallback callback)
133         {
134             if (n < 0)
135                 throw new ArgumentException();
136             if (n == 0)
137                 return;
138 
139             var result = new int[n - 1];
140             for (var i = 0; i < n; ++i)
141             {
142                 result[0] = i;
143                 if (!SubSet(n, i, 1, result, callback))
144                     return;
145             }
146         }
147 
148         static bool CartesianProduct(int[] sets, int i, int[] result, SetAlgorithmCallback callback)
149         {
150             for (var j = 0; j < sets[i]; ++j)
151             {
152                 result[i] = j;
153                 if (i == sets.Length - 1)
154                 {
155                     if (!callback(result, result.Length))
156                         return false;
157                 }
158                 else
159                 {
160                     if (!CartesianProduct(sets, i + 1, result, callback))
161                         return false;
162                 }
163             }
164             return true;
165         }
166         /// <summary>
167         /// 求集合笛卡尔积
168         /// </summary>
169         /// <param name="sets">包含集合元素个数的数组</param>
170         /// <param name="callback">回调函数</param>
171         public static void CartesianProduct(int[] sets, SetAlgorithmCallback callback)
172         {
173             int[] result = new int[sets.Length];
174             CartesianProduct(sets, 0, result, callback);
175         }
176     }
177 }

提供了以下几个通用的算法:

求排列  求组合  求集合真子集  求集合笛卡尔积

 没啥技术性,主要是泛用性.

例如: 已知3个集合 {"帽子1","帽子2","帽子3"}  {"上衣1","上衣2","上衣3"}  {"裤子a","裤子b"}

求所有的着装组合.可以使用笛卡尔积算法:

1             var c1= new string[]{"帽子1","帽子2","帽子3"};
2             var c2 = new string[] { "上衣1", "上衣2", "上衣3" };
3             var c3 = new string[] { "裤子a", "裤子b" };
4             SetAlgorithms.CartesianProduct(new int[] { c1.Length, c2.Length, c3.Length }, (result, len) =>
5             {
6                 Console.WriteLine("{0},{1},{2}", c1[result[0]], c2[result[1]], c3[result[2]]);
7                 return true;
8             });

其余的调用方法也类似. 举个更实际的例子,例如这帖的问题: http://topic.csdn.net/u/20110527/15/3f9ef827-988c-454c-8bf4-c44f48ec1fa2.html

例如,商品属性:

 品牌: 海尔 LG 三星 索尼 夏普 TCL 创维 长虹 飞利浦 康佳

 尺寸: 60寸以上 55寸 52寸 5 0寸 47寸 46寸 42寸 

液晶面板 : IPS硬屏面板 VA面板 ASV面板 黑水晶面板 X-GEN超晶面板

每个属性都是一个集合,列举出所有筛选可能,包括只选一个条件,现在是3个属性,如果属性个数不确定怎么实现

 对于这个问题.除去有未选的情况,我可以将结果集看做几个集合的笛卡尔集. 那对于未选状态怎么处理呢?我可以人为的为它的头部加上一个"未选"元素.例如品牌就变成了:

未选 海尔 LG 三星 索尼 夏普 TCL 创维 长虹 飞利浦 康佳

 1 var bands = new string[] { "海尔", "LG", "三星", "索尼", "夏普", "TCL", "创维", "长虹", "飞利浦", "康佳" };
 2 
 3             var size = new string[] { "60寸以上", "55寸", "52寸", "50寸", "47寸", "46寸", "42寸" };
 4 
 5             var types = new string[] {"IPS硬屏面板", "VA面板", "ASV面板", "黑水晶面板", "X-GEN超晶面板" };
 6 
 7             var array = new string[][] { bands, size, types };
 8             SetAlgorithms.CartesianProduct(new int[] { bands.Length + 1, size.Length + 1, types.Length + 1 }, (result, len) =>
 9             {
10                 for (var i = 0; i < array.Length; ++i)
11                 {
12                     if (result[i] == 0)//跳过"未选"
13                         continue;
14                     Console.Write("{0} ", array[i][result[i]-1]);
15                 }
16                 Console.WriteLine();
17                 return true;
18             });

 

posted @ 2015-09-17 17:46  维博.WILBUR  阅读(545)  评论(0编辑  收藏  举报