我需要使用k个同时使用方合并n个不同大小的已排序固定记录文件,其中k 由于文件的大小可能相差很大,因此在每个步骤使用所有k个使用者的简单贪婪方法可能不是最佳选择。 一个简单的例子清楚地说明了这一点。考虑4个文件的情况,分别具有1、1、10和10个记录以及3个使用者。我们需要两个合并步骤来合并所有文件。第一步,从3个消费者开始。合并序列((1,1,10),10)在(内部)步骤1中导致12次读/写操作,在(外部)步骤2中进行22次操作,总共进行34次操作。顺序(1,(1,10,10))在21 + 22 = 43 ops时甚至更糟。相反,如果我们在第一步中仅使用2个使用者,在第二步中使用3个使用者,则合并模式((1,1),10,10)仅占用2 + 22 = 24 ops。在这里,我们的克制得到了丰厚的回报。 我为每个步骤选择合适数量的消费者的解决方案如下。可以将所有可能的合并状态排序为一个有向图(我想是一个格子),将从一个状态移动到另一状态的操作数附加到每个边上,作为成本。然后,我可以使用最短路径算法来确定最佳顺序。 此解决方案的问题在于,即使文件数量适中(例如数百个),甚至在应用了一些合理的约束(例如按大小排序文件并仅允许合并前2个文件)后,节点数量也会爆炸。 .k)。而且,我无法撼动这种解决方案可能是“分析性”解决方案的感觉,或者至少是一种非常接近最优性的简单启发式方法。 任何想法都会受到赞赏。
答案 0 :(得分:0)
我可以用另一种方式提出它:
传统的合并排序复杂度为o(n.ln(n)),但在我的情况下,子列表大小不同,在最坏的情况下,如果一个文件很大而所有其他文件都很小(这就是您给出的示例),复杂度可能为o(nn):这是很差的性能复杂度。
问题是“如何以最佳方式安排子分类”?
预计算所有执行的图确实太大,在最坏的情况下它可能和您排序的数据一样大。
我的主张是“动态”计算它,让它不是最优的,但至少要避免更坏的情况。
我有K = 2: 在您的示例中1 1 10 10-> 2 20-> 22:仍然是(20 + 2)+ 22 CC,所以42 CC *
抄送:比较或复制:这是我计算的操作数,其复杂度为1。
如果我有K = 1并将结果重新注入到排序后的文件数组中,我得到: (1 1 10 10)-> 2 10 10-> 12 10->(22):2 CC + 12 + 22 = 46 对于不同的K值,复杂度略有不同
以概率计算平均情况下该算法的复杂性将是非常令人费解的,但是如果您可以接受一些针对坏情况的N²执行。
PS:
k<n
是另一个问题:通过将每两个文件中的一个工作线程添加到队列中(开始时为n / 2个工作线程),并通过k个线程读取该队列,可以简单地解决该问题。
答案 1 :(得分:0)
首先是另一种算法
read all record keys (N reads) with a fileid
sort them
read all files and place the records in the final position according to the sorted key (N R/W)
如果您的文件系统无法处理N + 1个打开的文件,或者您的随机文件访问速度较慢,则可能会出现问题。即随机读取或随机写入都会更快。
优点是N * 2次读取和N次写入。
返回您的算法
在合并中的任意点合并大文件和小文件是否值得?不
首先合并大文件是否值得?否
在最后一次合并中合并少于K个文件是否值得?是的
除第一次合并外,合并少于K个文件是否值得?是的
新启发式
while #files is larger than 1
sum size of smallest files until K or next larger file is greater than the sum.
K-merge these
ToDo证明在这种情况下的总和将小于所有其他方法。