不限单词数的完全组合函数
问题的提出和使用要素
近期一直使用VBA写程序,很多数据比对的地方需要把N个单词进行完全乱序的自由组合。用了很多循环之类的算法,但那都是在组合单词数已知的情况下进行,而且代码冗长又繁琐。
于是,在摸索了很久之后,终于想出了利用字典和递归算法的结合,写出了不受单词数限制的自由组合函数。
太兴奋了,忍不住发个博,跟大家分享。
备注(这是重点):
这个函数是在VBA里写的,但这不重要。
1、字典对象在现在的很多语言系统里都有,用法基本相同(参考的C#),就是一些细节的写法不同而已。
2、算法本身不受编程语言的限制。所以说,这个函数几乎可以移植到任何程序语言中去。
调用该函数的过程
非常简单
Sub test()
'设置一个字典,用于存储初值和结果
Set Dic_Rst = CreateObject("Scripting.Dictionary")
'给字典赋初值
Dic_Rst("A B C D E") = 0
'调用函数,结果就存在该字典中
Set Dic_Rst = ComposeWords(Dic_Rst)
End Sub
递归函数代码
也超级简单,不算格式、注释的话,连函数头尾,23行
注意:函数本身也是对象类型
Function ComposeWords(ByVal Dic_Rst As Object) As Object
'把字典中的最后一个Key提取出来
Last = Dic_Rst.Count - 1
StrArr = Dic_Rst.Keys()(Last)
tempArr = Split(StrArr) '拆分单词(默认空格分隔)
'递归思路:把每个单词提出来,分别做一次正向、一次反向组合"A B" "B A"
For Each FirstStr In tempArr
'除第一词FirstStr 之外,其余全部当成第二词对待。
SndStr = Application.Trim(Replace(StrArr, FirstStr, ""))
'递归中的递归:如果上面提取出来的“B”字串也是由多单词组成的,
'则重复一次递归的计算过程,把结果放在内层递归字典中
If InStr(SndStr, " ") Then
Set Dic_Snd = CreateObject("Scripting.Dictionary")
Dic_Snd(SndStr) = 0
Set d_SndStr = ComposeWords(Dic_Snd)
Else
Set d_SndStr = CreateObject("Scripting.Dictionary")
d_SndStr(SndStr) = 0
End If
'内层递归完成。无论它有几种组合,
'都用来和第一个提取词FirstStr 做正/反组合
For Each k2 In d_SndStr.Keys
tempCps1 = k2 + " " + FirstStr
tempCps2 = FirstStr + " " + k2
'存储组合结果(这里利用了字典的不重复和快速的特性)
If Not Dic_Rst.exists(tempCps1) Then Dic_Rst(tempCps1) = 0
If Not Dic_Rst.exists(tempCps2) Then Dic_Rst(tempCps2) = 0
Next
Next
'本次递归结束并赋值
Set ComposeWords = Dic_Rst
End Function