【发布时间】:2018-04-10 09:02:45
【问题描述】:
我有 800 个数据文件,每个文件包含 8 行整数,例如
17,1,2,3,4,5,6,7,10,11,12,13,15,16,20,22,24,26,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
16,1,2,3,4,5,6,7,8,9,10,11,12,16,17,21,26,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
23,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,20,23,25,26,28,29,35,36,,,,,,,,,,,,,,,,,,,,,,,,,,
27,8,9,11,12,13,14,15,17,19,20,21,22,23,24,26,27,28,29,30,31,32,34,37,39,40,41,42,,,,,,,,,,,,,,,,,,,,,,
27,14,16,17,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,35,36,37,38,39,40,42,43,44,,,,,,,,,,,,,,,,,,,,,,
24,20,24,26,27,28,29,30,31,32,33,34,35,36,37,39,40,41,42,43,44,45,46,47,48,,,,,,,,,,,,,,,,,,,,,,,,,
16,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,49,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
14,35,37,38,39,40,41,42,43,44,45,46,47,48,49,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
每行有 50 个元素,每行的第一个元素是数字计数,即第 1 行的 17 表示该行中有 17 个数字 1,2,3,4,5,6,7,10,11,12, 13、15、16、20、22、24、26。每行中的数字是唯一的,按升序排列,范围为 1~49。 我的任务是从这 8 行生成唯一 8 个数字组合的列表 即 A,B,C,D,E,F,G,H 第 1 行的 A,第 2 行的 B ... 第 8 行的 H
将生成24,517,914,624(17*16*23*27*27*24*16*14)个条目:
1,1,4,8,14,20,33,35
...
1,1,4,8,14,20,33,49
....
1,2,4,8,14,20,33,35
...
2,1,4,8,14,20,33,35
...
然后将 24,517,914,624 个条目列表处理如下:
i) 删除具有重复数字的条目,例如1,1,4,8,14,20,33,35 和 1,1,4,8,14,20,33,49 将被移除
ii) 按升序对每个条目中的编号进行排序,例如2,1,4,8,14,20,33,35 将变为 1,2,4,8,14,20,33,35
iii) 删除重复的条目,例如2,1,4,8,14,20,33,35 排序后与 1,2,4,8,14,20,33,35 相同,因此只有 1,2,4,8,14 的 1 个条目,20,33,35 将被保留 经过上述过程,可能还剩下大约1000万个条目(这是我想要的结果)
但是。处理 24,517,914,624 个条目数组几乎是不可能的任务, 因此我尝试了以下两种方法来解决问题(尝试删除具有重复数字的条目并为每个条目排序。
1)蛮力方法,使用8个嵌套for循环生成组合:
for (int i = 0; i < LineArr[0][0]; i++) {
for (int j = 0; j < LineArr[1][0]; j++) {
for (int k = 0; k < LineArr[2][0]; k++) {
for (int l = 0; l < LineArr[3][0]; l++) {
for (int m = 0; m < LineArr[4][0]; m++) {
for (int n = 0; n < LineArr[5][0]; n++) {
for (int o = 0; o < LineArr[6][0]; o++) {
for (int p = 0; p < LineArr[7][0]; p++) {
MyRes[0]=LineArr[0][i]
MyRes[1]=LineArr[1][j]
MyRes[2]=LineArr[2][k]
MyRes[3]=LineArr[3][l]
MyRes[4]=LineArr[4][m]
MyRes[5]=LineArr[5][n]
MyRes[6]=LineArr[6][o]
MyRes[7]=LineArr[7][p]
// Sort number of MyRes and discard if it contains duplicate numbers
// store valid combination in a temp array/vector
}}}}}}}}
// remove duplicate entries in the temp array/vector ('unique' the temp array)
2) 逐步方法 不是一次生成 8 个数字组合,而是从前 2 行生成 2 个数字组合,对每个条目中的数字进行排序,删除具有重复数字的条目并统一列表 输出将是这样的:
1,2
1,3
1,4
1,1 2,2 将被删除,4,1 将变为 1,4 并删除重复条目。
那么上面的列表将与第3行组合形成3个数字组合,同时对重复数字的条目进行排序和删除,并统一列表。 将上述应用到 4,5,6...8 行,形成 4,5,6...8 个数字组合
由于这是自动化项目的一部分,因此 AutoIt 在整个项目中都使用(这 800 个文件 来自另一个 3rd 方软件)。我尝试使用 AutoIt 实现组合生成, 技术上方法 1)生成 24,517,914,624 个条目,在生成后立即对每个条目中的编号进行排序,并丢弃其中包含重复编号的条目。 这种方法需要永远运行,因为它涉及数十亿个条目进行测试/排序,并且其数组大小远高于 AutoIt 的数组大小限制(1600 万)。因此方法 1) 可以被丢弃, 它只适用于(最多)5个数字组合(例如1,3,7,14,23)。
对于方法 2),我尝试了 2 种变体:
i) 将每个步骤中的结果存储在临时数组中,并使用 AutoIt 的 _ArrayUnique 函数删除重复条目。这也需要永远运行!
ii) 我没有将结果存储在 temp 数组中,而是使用 SQLite,即将每个步骤中生成的组合放入 SQLite 中的单行表中,使用 PRIMARY KEY UNIQUE 创建表/行然后我选择排回 AutoIt 进行进一步处理。
变体 ii) 最终起作用,处理 1 个文件需要 1 小时 20 分钟(我有 800 个这样的文件)
现在我打算在VC++(VS 2017)中实现组合生成,我有以下问题:
1) 除了“蛮力”和“逐步”之外,从性能的角度来看,还有其他方法/算法可以从多个数组/向量生成唯一组合吗?
2) 要对每个条目中的数字进行排序并检查每个条目中的重复数字,我认为 std::sort, std::search/std::find 会完成这项工作,因为将有数百万个条目需要检查,从性能的角度来看,还有其他选择吗?
3) 要删除重复条目(统一组合列表,即获取唯一组合),我应该使用 std::unique 还是仍然依赖 SQLite ?因为数组的大小可能大到 30~40 百万,在 std::sort 和 std::unique 或 SQLite 的 SELECT 之后缩小到 1000 万(不知道从性能角度来看哪个实现更好)
4) 任何现成的 LIB 都可以轻松完成任务?
非常感谢。
注册表
林志峰
【问题讨论】:
标签: c++ arrays vector unique combinations