1
/*
2
=========程序信息========
3
模块简介:组合生成类,从m个数中取出n个数进行组合,其中m > n(非递归生成)
4
版本号:1.0
5
使用语言:c#
6
使用编译器:Visual Studio 2005 .NET
7
每次生成组合所需时间:O(n)
8
作者:贵州大学05级 刘永辉
9
昵称:SDJL
10
编写时间:2008年8月
11
联系QQ:44561907
12
E-Mail:44561907@qq.com
13
获得更多文章请访问我的博客:www.cnblogs.com/sdjl
14
如果发现BUG或有写得不好的地方请发邮件告诉我:)
15
==========算法介绍=======
16
我们先来看m=5、n=3的组合情况,如下:
17
1 2 3
18
1 2 4
19
1 2 5
20
1 3 4
21
1 3 5
22
1 4 5
23
2 3 4
24
2 3 5
25
2 4 5
26
3 4 5
27
仔细观察会发现下面的特性(这些特性对于m、n取任何值均成立):
28
1、我们可以从前n个数开始进行组合
29
2、每一次获得下一个组合时只要把最后一个数加1即可
30
3、如果最后一个数达到了上界,即不能再增加时,则考虑增加前一个数,同样,如果前一个数也达到上界时,那么就增加前前一个数,依此类推
31
4、不同的位置的数的上界不同,且从右向左依次减小,最后一个是n,第一个是 m-n+1
32
5、当第i个数增加1且i不等于n时,需要改变第i个数右面的所有数的值,并且是从第i个数开始依次增加1
33
6、当出现最大的n个数组成的组合后,所有的组合均已生成一遍
34
*/
35
36
using System;
37
using System.Collections.Generic;
38
using System.Text;
39
40
namespace SDJL.Combination
41
{
42
/// <summary>
43
/// 组合类[Write by SDJL]
44
/// version:1.0
45
/// </summary>
46
public class Combination
47
{
48
/// <summary>
49
/// m个数的数组
50
/// </summary>
51
private object[] m_datas;
52
/// <summary>
53
/// 用于记录当前状态,
54
/// </summary>
55
/// <example>
56
/// m_state[0]=3 表示生成的组合中第0个元素为所有元素中的第3个
57
/// </example>
58
private int[] m_state;
59
/// <summary>
60
/// 总元素个数
61
/// </summary>
62
private int m_m;
63
/// <summary>
64
/// 取出元素个数
65
/// </summary>
66
private int m_n;
67
/// <summary>
68
/// 是否还有下一个组合
69
/// </summary>
70
private bool m_hasNext = true;
71
72
/// <summary>
73
/// 是否还有下一个组合
74
/// </summary>
75
public bool HasNext
76
{
77
get { return m_hasNext; }
78
}
79
80
/// <summary>
81
/// 用数组构造组合
82
/// O(m)
83
/// </summary>
84
/// <param name="datas">源数组</param>
85
/// <param name="n">提取的元素个数</param>
86
public Combination(object[] datas,int n)
87
{
88
m_datas = datas;
89
m_n = n;
90
m_m = datas.Length;
91
m_state = new int[m_n];
92
for (int i = 0; i < m_n; i++)
93
{
94
m_state[i] = i;
95
}
96
}
97
98
/// <summary>
99
/// 构造基于整数的组合
100
/// O(m)
101
/// </summary>
102
/// <param name="m">总共拥有的整数数</param>
103
/// <param name="n">提取元素个数</param>
104
public Combination(int m, int n)
105
{
106
m_n = n;
107
m_m = m;
108
109
m_datas = new object[m_m];
110
for (int i = 0; i < m_m; i++)
111
{
112
m_datas[i] = i;
113
}
114
115
m_state = new int[m_n];
116
for (int i = 0; i < m_n; i++)
117
{
118
m_state[i] = i;
119
}
120
}
121
122
/// <summary>
123
/// 获取下一个组合
124
/// O(n)
125
/// </summary>
126
/// <returns>当所有组合均获取完毕后返回null</returns>
127
public object[] Next()
128
{
129
object[] returnArray = null;
130
if (m_hasNext)
131
{
132
returnArray = MakeArray();
133
EnterNextState();
134
}
135
return returnArray;
136
}
137
138
/// <summary>
139
/// 用状态[m_state]生成组合数组
140
/// O(n)
141
/// </summary>
142
/// <returns></returns>
143
private object[] MakeArray()
144
{
145
object[] returnArray = new object[m_n];
146
for (int i = 0; i < m_n; i++)
147
{
148
returnArray[i] = m_datas[m_state[i]];
149
}
150
151
return returnArray;
152
}
153
154
/// <summary>
155
/// 进入下一个状态
156
/// O(n)
157
/// </summary>
158
/// <returns>
159
/// 当下一个状态存在时返回true,否则返回false
160
/// </returns>
161
private bool EnterNextState()
162
{
163
//k是需要增加1的那个数,起初假设k是最后一个,注意程序中是从0开始编号
164
int k = m_n - 1;
165
//根据前面的分析,寻找到k的值
166
while ((k >= 0) && (m_state[k] + (m_n - k) == m_m))
167
{
168
k--;
169
}
170
//如果找到一个需要增加1的数
171
if (k>=0)
172
{
173
//如果这个数在最后的位置上
174
if (k==m_n-1)
175
{
176
//给这个数增加1
177
m_state[k]++;
178
}
179
else//否则这个数不在最后的位置上
180
{
181
//给这个数增加1
182
m_state[k]++;
183
k++;
184
//改变这个数后面的所有数的值,使得他们的值依次增加1
185
while (k<m_n)
186
{
187
m_state[k] = m_state[k - 1] + 1;
188
k++;
189
}
190
}
191
m_hasNext = true;
192
}
193
else//否则找不到需要增加1的数
194
{
195
//已经不能再次生成组合了
196
m_hasNext = false;
197
}
198
return m_hasNext;
199
}
200
}
201
}
202
/*2
=========程序信息========3
模块简介:组合生成类,从m个数中取出n个数进行组合,其中m > n(非递归生成)4
版本号:1.05
使用语言:c#6
使用编译器:Visual Studio 2005 .NET7
每次生成组合所需时间:O(n)8
作者:贵州大学05级 刘永辉 9
昵称:SDJL10
编写时间:2008年8月11
联系QQ:4456190712
E-Mail:44561907@qq.com13
获得更多文章请访问我的博客:www.cnblogs.com/sdjl14
如果发现BUG或有写得不好的地方请发邮件告诉我:)15
==========算法介绍=======16
我们先来看m=5、n=3的组合情况,如下:17
1 2 318
1 2 419
1 2 520
1 3 421
1 3 522
1 4 523
2 3 424
2 3 525
2 4 526
3 4 527
仔细观察会发现下面的特性(这些特性对于m、n取任何值均成立):28
1、我们可以从前n个数开始进行组合29
2、每一次获得下一个组合时只要把最后一个数加1即可30
3、如果最后一个数达到了上界,即不能再增加时,则考虑增加前一个数,同样,如果前一个数也达到上界时,那么就增加前前一个数,依此类推31
4、不同的位置的数的上界不同,且从右向左依次减小,最后一个是n,第一个是 m-n+132
5、当第i个数增加1且i不等于n时,需要改变第i个数右面的所有数的值,并且是从第i个数开始依次增加133
6、当出现最大的n个数组成的组合后,所有的组合均已生成一遍34
*/35

36
using System;37
using System.Collections.Generic;38
using System.Text;39

40
namespace SDJL.Combination41
{42
/// <summary>43
/// 组合类[Write by SDJL]44
/// version:1.045
/// </summary>46
public class Combination47
{48
/// <summary>49
/// m个数的数组50
/// </summary>51
private object[] m_datas;52
/// <summary>53
/// 用于记录当前状态,54
/// </summary>55
/// <example>56
/// m_state[0]=3 表示生成的组合中第0个元素为所有元素中的第3个57
/// </example>58
private int[] m_state;59
/// <summary>60
/// 总元素个数61
/// </summary>62
private int m_m;63
/// <summary>64
/// 取出元素个数65
/// </summary>66
private int m_n;67
/// <summary>68
/// 是否还有下一个组合69
/// </summary>70
private bool m_hasNext = true;71
72
/// <summary>73
/// 是否还有下一个组合74
/// </summary>75
public bool HasNext76
{77
get { return m_hasNext; }78
}79

80
/// <summary>81
/// 用数组构造组合82
/// O(m)83
/// </summary>84
/// <param name="datas">源数组</param>85
/// <param name="n">提取的元素个数</param>86
public Combination(object[] datas,int n) 87
{88
m_datas = datas;89
m_n = n;90
m_m = datas.Length;91
m_state = new int[m_n];92
for (int i = 0; i < m_n; i++)93
{94
m_state[i] = i;95
}96
}97

98
/// <summary>99
/// 构造基于整数的组合100
/// O(m)101
/// </summary>102
/// <param name="m">总共拥有的整数数</param>103
/// <param name="n">提取元素个数</param>104
public Combination(int m, int n)105
{106
m_n = n;107
m_m = m;108

109
m_datas = new object[m_m];110
for (int i = 0; i < m_m; i++)111
{112
m_datas[i] = i;113
}114
115
m_state = new int[m_n];116
for (int i = 0; i < m_n; i++)117
{118
m_state[i] = i;119
}120
}121

122
/// <summary>123
/// 获取下一个组合124
/// O(n)125
/// </summary>126
/// <returns>当所有组合均获取完毕后返回null</returns>127
public object[] Next()128
{129
object[] returnArray = null;130
if (m_hasNext)131
{132
returnArray = MakeArray();133
EnterNextState();134
}135
return returnArray;136
}137

138
/// <summary>139
/// 用状态[m_state]生成组合数组140
/// O(n)141
/// </summary>142
/// <returns></returns> 143
private object[] MakeArray()144
{145
object[] returnArray = new object[m_n];146
for (int i = 0; i < m_n; i++)147
{148
returnArray[i] = m_datas[m_state[i]];149
}150

151
return returnArray;152
}153
154
/// <summary>155
/// 进入下一个状态156
/// O(n)157
/// </summary>158
/// <returns>159
/// 当下一个状态存在时返回true,否则返回false160
/// </returns> 161
private bool EnterNextState()162
{163
//k是需要增加1的那个数,起初假设k是最后一个,注意程序中是从0开始编号164
int k = m_n - 1;165
//根据前面的分析,寻找到k的值166
while ((k >= 0) && (m_state[k] + (m_n - k) == m_m))167
{168
k--;169
}170
//如果找到一个需要增加1的数171
if (k>=0)172
{173
//如果这个数在最后的位置上174
if (k==m_n-1)175
{176
//给这个数增加1177
m_state[k]++;178
}179
else//否则这个数不在最后的位置上180
{181
//给这个数增加1182
m_state[k]++;183
k++;184
//改变这个数后面的所有数的值,使得他们的值依次增加1185
while (k<m_n)186
{187
m_state[k] = m_state[k - 1] + 1;188
k++;189
}190
}191
m_hasNext = true;192
}193
else//否则找不到需要增加1的数194
{195
//已经不能再次生成组合了196
m_hasNext = false;197
}198
return m_hasNext;199
}200
}201
}202



浙公网安备 33010602011771号