|
wcymiss 发表于 2012-11-17 01:45
1、数学中常用的是n是总数,m是选取数。
2、排列组合是经典问题,代码一般也比较程式化。下面的代码应该是 ...
2楼吴姐do……loop循环代码很简洁高效,
我改成了可以根据外部数据生成组合结果的实用性代码:- Sub GetCombin_wcy()
- tms = Timer
- Dim i%, j%, s&, t$
- '原始数据放置在A1开始的A列中。
- n = [a1].End(4).Row '获取原始数据个数(A列最大行数)
- sj = [a1].Resize(n) '原始数据各元素读入数组sj
- m = [b1] 'B1单元格中写入需要抽取的元素个数
- ReDim a%(1 To m) '数组a用来存放各个数位的当前组合状态
- ' ReDim b%(1 To m) '这个存放上界值的数组可以省略不用,以后在代码中直接计算得到。
- '以下为数组a初始化,存入1,2,3,4……
- '以及把组合最终结果(根据原始数据相应转换后的结果)存入字符变量t
- a(1) = 1
- If m > 1 Then t = sj(1, 1) Else t = ""
- For i = 2 To m - 1
- a(i) = i
- t = t & ";" & sj(i, 1)
- Next
- a(m) = m
- s = WorksheetFunction.Combin(n, m) '计算组合结果总数
- ReDim jg(1 To s, 1 To 1) '定义相应大小的存放结果的数组
- k = 1 '当前组合结果数初始化
- i = m '循环指针初始化,从末位开始
- Do
- If i = m Then '如果参与组合的元素个数达到m个即可输出本次组合结果
- ' Debug.Print Join(a, " ") '代码调试时可以观察到组合变换。
- jg(k, 1) = t & ";" & sj(a(m), 1) '本次组合的文本字符串结果存入jg数组
- '(算法是1~m-1的组合结果t,加上当前末位指针所指元素)
- k = k + 1 '组合结果数递增1 (仅仅为了能够依次把组合结果存入数组jg中去)
- End If
-
- If a(i) < n - m + i Then '检查各数位是否可以递增1,以便生成新的组合结果
- a(i) = a(i) + 1 '可以递增时直接递增即可。
- If i < m Then '如果本数位i不是末位m,那么除了本数位递增1以外,其余后面各位还要阶梯递增对齐
- For i = i To m - 1 '这里写成i to m-1,而实际做的是 i+1 to m
- a(i + 1) = a(i) + 1 '实际循环结果,是从本位+1开始直到末位,全部向前位+1对齐
- Next
- '以上为止是对各个数位的序列状态进行组合变化,结果存放在数组a中,如 1,2,3;3,4,6等
- '但需要通过下面几句代码,把组合序号对应的原始数据元素取出。
- t = sj(a(1), 1) '字符变量t中存入组合第一位序号a(1)对应元素,如a(1)=3就取第3个元素。
- For j = 2 To m - 1
- t = t & ";" & sj(a(j), 1) '循环从第2数位直到m-1数位,结果依次取出合并到字符变量t中
- Next
- End If
- Else '当检查该数位不可以递增1时
- i = i - 1 '数位指针i-1处理,以便进入下一次循环检查前面i-1数位位置的状态是否可以递增……
- End If
- Loop Until i = 0 '重复do……loop循环直至检查到i=0,即i=1也不能递增时,结束循环。
- MsgBox k - 1 & vbCr & Format(Timer - tms, "0.000s") '输出 组合结果总数,以及组合算法耗用时间
- '以下为输出所有组合结果到工作表
- tms = Timer
- [d:d] = ""
- [d1].Resize(s) = jg
- [d1].EntireColumn.AutoFit
- MsgBox Format(Timer - tms, "0.000s")
- End Sub
复制代码 |
评分
-
查看全部评分
|