当前位置: 首页 > 知识库问答 >
问题:

N路合并算法

郭志泽
2023-03-14

作为Mergesort算法的一部分,双向合并被广泛研究。但我有兴趣找出执行N路合并的最佳方法?

比方说,我有N个排序100万整数的文件。我必须将它们合并成1个文件,其中会有那些1亿排序的整数。

请记住,这个问题的用例实际上是基于磁盘的外部排序。因此,在实际场景中也会存在内存限制。因此,一次(99次)合并两个文件的天真方法是行不通的。假设每个阵列只有一个小的内存滑动窗口。

我不确定是否已经有一个标准化的解决方案来解决这个N路合并。(谷歌搜索没有告诉我太多)。

但是如果你知道一个好的n路合并算法,请张贴algo/link。

时间复杂度:如果我们大大增加了要合并的文件(N)的数量,这将如何影响算法的时间复杂度?

谢谢你的回答。

我在任何地方都没有被问过这个问题,但我觉得这可能是一个有趣的面试问题。因此标记。

共有3个答案

夏侯昆琦
2023-03-14

一个简单的想法是保留要合并的范围的优先级队列,存储方式是首先从队列中删除第一个元素最小的范围。然后,您可以执行如下N路合并:

  1. 将所有范围插入优先级队列,不包括空范围

这种算法的正确性本质上是证明双向合并正确工作的推广——如果你总是从任何范围中添加最小的元素,并且所有的范围都被排序,你最终会把序列作为一个整体排序。

该算法的运行时复杂性如下所示。设M是所有序列中元素的总数。如果我们使用二进制堆,那么我们从优先级队列中最多执行O(M)个插入和O(M)个删除,因为对于写入输出序列的每个元素,都有一个出列以拉出最小序列,然后是一个排队以将序列的其余部分放回队列。每个步骤都需要O(lgn)操作,因为从包含N个元素的二进制堆中插入或删除需要O(lgn)时间。这给出了一个O(mlgn)的净运行时间,它与输入序列的数量成线性关系。

也许有一种方法可以更快地实现这一点,但这似乎是一个很好的解决方案。内存使用量为O(N),因为二进制堆需要O(N)开销。如果我们通过存储指向序列的指针而不是序列本身来实现二进制堆,这应该不会有太大的问题,除非你有一个非常荒谬的序列数量要合并。在这种情况下,只需将它们合并到适合内存的组中,然后合并所有结果。

希望这有帮助!

叶经略
2023-03-14

搜索“多相合并”,查看经典-Donald Knuth

此外,你可能想看看由Seyedafsari提出的智能块合并

另一个有趣的理由是Kim的就地合并算法

我还推荐Vitter的这篇论文:外部内存算法和数据结构:处理海量数据。

海岳
2023-03-14

以下想法如何:

  1. 创建优先级队列
  2. 遍历每个文件f
    1. 使用第一个值作为优先级键对(nextNumberIn(f), f)进行排队
    1. 队列的出列头(m,f)
    2. 输出m
    3. 如果f没有耗尽
      1. 排队(下一个编号(f),f)

      因为向优先级队列添加元素可以在对数时间内完成,所以第2项是O(N×logn)。由于while循环的(几乎所有)迭代都添加了一个元素,因此整个while循环是O(M×logn),其中M是要排序的数字总数。

      假设所有文件都有一个非空的数字序列,我们有M

 类似资料:
  • 我知道合并排序算法的基本概念,但是当涉及到通过递归实现它时,我很难理解它是如何工作的。据我所知,合并排序函数将我们当前的数组分成两半,并使用递归我们一直这样做,直到每边只剩下一个元素。 如果我们的数组是{38、27、43、3、9、82、10},那么我们的递归将从使用子数组(原始数组的左侧)调用自身开始,并每次重复该过程,将数组减半并存储最左侧,直到达到1个元素: 然后在我们的第二个子例程中,我们继

  • 问题是关于从16:43到23:34的视频中的合并排序http://youtu.be/M814OagXWTI?t=16m43s 在退出左/右排序合并递归后,我不清楚我们是如何合并回这些子数组的。让我们从最底部开始,当我们的元素被分成两个子数组时,一个左子数组称为B,一个右子数组称为C。在16:43左右,我们跳转到合并函数,对数组B和C进行排序,这两个数组只有8和3。合并排序函数(下面的代码)基本上通

  • 本文向大家介绍JavaScript中合并数组的N种方法,包括了JavaScript中合并数组的N种方法的使用技巧和注意事项,需要的朋友参考一下 这是一篇简单的文章,关于JavaScript数组使用的一些技巧。我们将使用不同的方法结合/合并两个JS数组,以及讨论每个方法的优点/缺点。 让我们先考虑下面这情况: 很显然最简单的结合结果应该是: concat(..) 这是最常见的做法: 正如你所看到的,

  • 主要内容:RxJava 合并运算符 介绍,RxJava 合并运算符 示例RxJava 合并运算符 介绍 以下是用于从多个 Observable 创建单个 Observable 的运算符。 运算符 描述 And/Then/When 使用模式和计划中介组合项目集。 CombineLatest 通过指定的函数组合每个 Observable 发出的最新项并发出结果项。 Join 如果在第二个 Observable 发射项目的时间范围内发送,则组合两个 Observable 发

  • 问题内容: 我看着一个合并标记,看起来都搞砸了。为了给您带来这种情况,让我们这样做: 现在进行合并(我使用SourceTree进行拉取)。标记看起来像这样: 因此,拉出的提交所做的是完全删除methodA并添加methodB。 但是您注意到有些行完全丢失了。 据我了解的过程,Git正在尝试一种所谓的自动合并,如果失败并在检测到冲突时发生冲突,则完全合并将由标有’<<< * HEAD’+ + +’=

  • 我在理解外部排序算法中的合并步骤时遇到了一定的困难。我在维基百科上看到了这个例子,但我无法理解。 外部排序的一个例子是外部合并排序算法,它对每个适合RAM的块进行排序,然后将排序后的块合并在一起。例如,对于仅使用100 MB RAM对900 MB数据进行排序:1)读取主内存中的100 MB数据,并通过一些常规方法进行排序,如快速排序。2) 将排序后的数据写入磁盘。3) 重复第1步和第2步,直到所有