什么是合并k列表的最佳方式?

时间:2014-10-05 05:17:32

标签: algorithm sorting merge

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

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

我遇到两件事情有困难:1。这是否确实是最优的(还有另一种方法会在更快的时间内返回)吗? 2.当我们合并时,我们如何分析列表大小变化时的运行时间?

1 个答案:

答案 0 :(得分:1)

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

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

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

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