【问题标题】:What's the optimal way to merge k lists?合并 k 个列表的最佳方法是什么?
【发布时间】:2014-10-05 05:17:31
【问题描述】:

假设您有一个合并函数,它将在 O(s1+s2) 时间内合并(查找)两个大小为 s1 和 s2 的列表 L1 和 L2 的并集。合并 k 个大小为 s1、s2、...、sk 的列表的最佳方法是什么?

我在想我们应该首先对 s1, ..., sk 进行排序,然后对与最小的两个大小相对应的前两个列表进行排序。当这些被合并时,我们在排序后的大小列表中找到它们的大小位置并继续该过程,直到我们最终得到一个列表。

我在两件事上遇到了麻烦:1. 这是否确实是最佳的(是否有另一种方法可以更快地返回)? 2. 合并时列表大小发生变化时如何分析运行时间?

【问题讨论】:

    标签: algorithm sorting merge


    【解决方案1】:

    精确地与为由已知频率s<sub>1</sub>, s<sub>2</sub>, … s<sub>k</sub>k 符号的字母表组成的字符串找到最佳可变长度位编码的问题相同。您的算法正是Huffman algorithm,您可以在任何关于算法的教科书(以及许多在线资源)中找到最优性证明,因为它是具有简单正确性证明的贪心算法的经典案例。

    双向合并的重复应用会产生一棵二叉树,其中每个节点都是一个合并。给定那棵树,任何叶子对整体合并总成本的贡献是该叶子的权重乘以其在树中的深度。 (每个节点都是一个合并,叶子中的值完全参与从叶子到根的路径中的合并;这种合并的数量是树中叶子的深度。)类似地 - 或相同地 - -,霍夫曼编码的比特串的总长度是符号的权重(频率)与构造树中该符号对应的叶子深度的乘积之和。

    您的算法的一个小改进(编写 Huffman 树构建器的人经常忽略):有必要对权重进行排序s<sub>1</sub>, s<sub>2</sub>, … s<sub>k</sub>,但这是唯一需要的排序。从那里,算法总是选择两个最低的节点并将它们相加。结果总和的大小必须是单调非递减的(如果总和小于前一个总和,则前一个总和不可能是两个最小元素的总和)。所以你可以把总和放在一个队列中;在每个步骤中,您从排序的叶子数组或(隐式)排序的节点队列中选择两个最小的元素。

    这可以通过用节点队列覆盖叶子数组来进一步优化。 (然后队列从数组底部向顶部增长;证明队列顶部永远不会超过数组底部是相当简单的。)

    【讨论】:

    • 优秀的答案!谢谢你。您能否详细说明为什么我们只需要对权重进行一次排序?假设权重的排序列表是 s1,s2,...,sk。然后算法将合并对应于 s1 和 s2 的列表以产生 s12,“排序”列表现在看起来像 s12, s3, ..., sk。但是 s12+s3 可能比 s3+s4 大。
    • 或者是:如果我们的排序大小是s1,s2,...,sk 对应列表L1,L2,...Lk,那么我们先将L1和L2合并到L12,然后再合并L3和 L4 进入 L34 以获得 L12、L34、...、Lk-1Lk 并继续这个过程直到我们只剩下一个列表?如果是这样,当列表的数量是奇数时我们该怎么办?例如,如果我们有 L1、L2、L3、L4、L5,迭代将如下所示:L12、L34、L5 -> L1234、L5 -> L12345?
    • @BobJonas:有两个列表:叶子列表(不断变小)和化合物列表(不断增长)。最初,化合物是空的。我们从 s1,s2,s3,s4;- 开始。第一步之后,我们有(s1,s2),s3,s4,...;s12。 (括号中的元素被删除。)如果s3s4 现在是最小的(s12&gt;s4),那么我们就有(s1,s2,s3,s4),s5,s6,...;s12,s34。否则s3s12 是最小的两个,我们将有(s1,s2,s3),s4,s5,...;(s12),s123。我们还必须查看三个元素来选择最小的两个:每个列表中最小的,以及...
    • ...列表中第一个元素最小的第二个最小元素。关键是复合列表不需要排序,因为它是按排序顺序产生的,叶子列表排序一次并保持排序。实际上,我们合并了两个排序列表,但其中一个列表是延迟生成的。最后,两个列表都是空的,但是如果我们移动指针而不是删除,我们有一个排序的叶子列表和一个排序的化合物列表。如果我们使用相同的数组,化合物会覆盖删除的叶子。
    • 好的,谢谢!老实说,唯一对我来说没有意义的是我们如何分析运行时间。因为如果叶子可以在数组中移动,那么我们怎么知道哪些叶子需要到达根,或者,就此而言,它们中的任何一个的深度是多少?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多