Algorithm 如何在O(n*log(k))中将已排序的列表合并为单个列表

Algorithm 如何在O(n*log(k))中将已排序的列表合并为单个列表,algorithm,sorting,Algorithm,Sorting,(这是我作为面试问题得到的,我希望得到一些帮助。) 您有k已排序的列表,其中总共包含n不同的数字。 演示如何创建一个单独的排序列表,其中包含O(n*log(k))中k个列表中的所有元素。方法是使用大小为k的 推送堆上的所有k个列表(每个列表一个堆条目),按其最小值(即第一个)键入 然后重复这样做: 从堆中提取顶部列表(具有最小键) 从该列表中提取最小值并将其推送到结果列表中 将缩短的列表向后推(如果它不是空的)到堆上,现在由其新的最小值键入 重复此操作,直到结果列表上的所有值都已按下 初始步骤的

(这是我作为面试问题得到的,我希望得到一些帮助。)

您有
k
已排序的列表,其中总共包含
n
不同的数字。
演示如何创建一个单独的排序列表,其中包含
O(n*log(k))中k个列表中的所有元素。

方法是使用大小为k的

推送堆上的所有k个列表(每个列表一个堆条目),按其最小值(即第一个)键入

然后重复这样做:

  • 从堆中提取顶部列表(具有最小键)
  • 从该列表中提取最小值并将其推送到结果列表中
  • 将缩短的列表向后推(如果它不是空的)到堆上,现在由其新的最小值键入
  • 重复此操作,直到结果列表上的所有值都已按下

    初始步骤的时间复杂度为O(klogk)

    上述3个步骤将重复n次。在每次迭代中,每次迭代的成本为:

  • O(1)
  • O(1)如果使用指针/索引实现提取(不移动列表中的所有值)
  • O(log k),因为堆大小从不大于k
  • 因此,得到的复杂度是O(nlogk)(当k我们的想法是使用大小为k的a

    推送堆上的所有k个列表(每个列表一个堆条目),按其最小值(即第一个)键入

    然后重复这样做:

  • 从堆中提取顶部列表(具有最小键)
  • 从该列表中提取最小值并将其推送到结果列表中
  • 将缩短的列表向后推(如果它不是空的)到堆上,现在由其新的最小值键入
  • 重复此操作,直到结果列表上的所有值都已按下

    初始步骤的时间复杂度为O(klogk)

    上述3个步骤将重复n次。在每次迭代中,每次迭代的成本为:

  • O(1)
  • O(1)如果使用指针/索引实现提取(不移动列表中的所有值)
  • O(log k),因为堆大小从不大于k

  • 因此,得到的复杂度是O(nlogk)(当k
    n=2
    时,通过反复弹出列表的最前面来合并两个列表,该列表是最小的。在某种程度上,您可以创建一个虚拟列表,该列表支持实现为以下操作的
    pop_front
    操作:

    pop_front(a, b): return if front(a) <= front(b) then pop_front(a) else pop_front(b)
    

    N=2
    时,通过反复弹出列表的最前面来合并两个列表,该列表是最小的。在某种程度上,您可以创建一个虚拟列表,该列表支持实现为以下操作的
    pop_front
    操作:

    pop_front(a, b): return if front(a) <= front(b) then pop_front(a) else pop_front(b)
    

    正如问题所述,不需要k路合并(或堆)。重复使用标准的双向合并,以任意顺序合并列表对,直到生成单个排序列表,其时间复杂度也为O(n log(k))。如果问题是如何在一次过程中合并k个列表,那么就需要k路合并

    考虑k==32的情况,为了简化数学,假设所有列表按顺序合并,以便每个合并过程合并所有n个元素。在第一次传递之后,有k/2个列表,在第二次传递之后,有k/4个列表,在log2(k)=5次传递之后,所有k(32)个列表合并为一个排序列表。除了简化数学之外,列表合并的顺序无关紧要,时间复杂度在O(nlog2(k))下保持不变


    通常,只有在使用外部设备(如一个或多个磁盘驱动器(或传统用法的磁带驱动器))合并数据时,使用k路合并才有好处,因为在这些设备中,I/O时间足够长,可以忽略堆开销。对于基于ram的合并/合并排序,2路合并/合并排序或k路合并/合并排序的操作总数大致相同。在具有16个寄存器(其中大多数用作索引或指针)的处理器上,优化的(无堆)4路合并(使用8个寄存器作为索引或指向每次运行的当前和结束位置的指针)可能比2路合并快一点,因为它对缓存更为友好

    正如问题所述,不需要k路合并(或堆)。重复使用标准的双向合并,以任意顺序合并列表对,直到生成单个排序列表,其时间复杂度也为O(n log(k))。如果问题是如何在一次过程中合并k个列表,那么就需要k路合并

    考虑k==32的情况,为了简化数学,假设所有列表按顺序合并,以便每个合并过程合并所有n个元素。在第一次传递之后,有k/2个列表,在第二次传递之后,有k/4个列表,在log2(k)=5次传递之后,所有k(32)个列表合并为一个排序列表。除了简化数学之外,列表合并的顺序无关紧要,时间复杂度在O(nlog2(k))下保持不变


    通常,只有在使用外部设备(如一个或多个磁盘驱动器(或传统用法的磁带驱动器))合并数据时,使用k路合并才有好处,因为在这些设备中,I/O时间足够长,可以忽略堆开销。对于基于ram的合并/合并排序,2路合并/合并排序或k路合并/合并排序的操作总数大致相同。在具有16个寄存器(其中大多数用作索引或指针)的处理器上,优化的(无堆)4路合并(使用8个寄存器作为索引或指向每次运行的当前和结束位置的指针)可能比2路合并快一点,因为它对缓存更为友好

    查找。什么编程语言?这与合并排序仍不完全相同,因此我想值得一问。在提出问题之前,您应该尝试使用查找的或?可能的副本。什么编程语言?这与合并排序仍不完全相同,所以我想这是值得一问的。在问问题之前,你应该尝试使用元组
    (元素,索引,n
    
        5 7 32 21
      5
        6 4 8 23 40
    2
        7 7 20 53
      2
        2 4 6 8 10