从多个数组/向量生成唯一组合

时间:2018-04-10 09:02:46

标签: c++ arrays vector unique combinations

我有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 A从第1行开始,B从第2行开始...... H从第8行开始

将会生成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个文件 来自另一个第三方软件)。我尝试用AutoIt实现组合生成, 技术上方法1)生成24,517,914,624个条目,在生成后立即对每个条目中的排序编号进行排序,并丢弃其中包含重复编号的条目。 这种方法需要永远运行,因为它涉及数十亿条目进行测试/排序,其数组大小远高于AutoIt的数组大小限制(1600万)。因此方法1)可以丢弃, 它只适用于(最多)5个数字组合(例如1,3,7,14,23)。

对于方法2),我尝试了两种变体:

i)将结果存储在临时数组的每一步中,并使用AutoIt的_ArrayUnique函数删除重复的条目。这也需要永远运行!!

ii)我没有将结果存储在临时数组中,而是使用SQLite,即将每个步骤中生成的组合放入SQLite中的单个行表中,使用PRIMARY KEY UNIQUE创建表/行然后我选择返回AutoIt进行进一步处理。

变异ii)最终工作,处理1个文件需要1小时20分钟(我有800个这样的文件)

现在我打算在VC ++(VS 2017)中实现组合生成,我有以下问题:

1)除了&#34;蛮力&#34;和#34;逐步&#34;,从性能的角度来看,从多个数组/向量生成唯一组合的任何其他方法/算法?

2)要对每个条目中的数字进行排序并检查每个条目中的重复数字,我认为std :: sort,std :: search / std :: find将完成这项工作,但是,因为将有数百万条目要检查,从绩效的角度来看还有其他选择吗?

3)要删除重复的条目(统一组合列表,即获得唯一的组合),我应该使用std :: unique还是仍然依赖SQLite?因为数组的大小可能高达30~40百万,并且在SQLite的std :: sort和std :: unique或SELECT之后缩小到1000万(不知道哪种实现在性能上更好)< / p>

4)任何现成的LIB都可以轻松完成任务吗?

非常感谢。

Regds

林志峰

1 个答案:

答案 0 :(得分:0)

找出std :: set,它的排序/独特功能适合我的需要。我用它实现逐步方法,程序像fly一样运行。只有它在第6行之后容易出现内存,所以我将它与SQLite结合,即在6行上工作后,我丢弃std :: set并将组合结果存储在SQLite表中(单行表与PRIMARY KEY UNIQUE)。这可能不是一个完美的解决方案,但可行。