为什么迭代k-way合并O(nk ^ 2)?

时间:2012-06-14 03:21:29

标签: algorithm

k-way merge是一种算法,它采用大小为n的输入k排序数组。它输出所有元素的单个排序数组。

它通过使用合并排序算法中心的“合并”例程将数组1合并到数组2,然后将数组3合并到此合并数组,依此类推,直到所有k个数组合并为止。

我原以为这个算法是O(kn)因为算法遍历每个k个数组(每个长度为n)一次。为什么是O(nk ^ 2)?

9 个答案:

答案 0 :(得分:60)

因为它不会遍历每个k数组一次。第一个数组遍历k-1次,第一个数组为merge(array-1,array-2),第二个数组为merge(merge(array-1,array-2),array-3)...依此类推

结果是k-1与平均大小n *(k + 1)/ 2合并,给出O(n *(k ^ 2-1)/ 2)的复杂度,即O(nk ^ 2)

你犯的错误是忘记了合并是串行完成而不是并行完成,所以数组的大小都不是n。

答案 1 :(得分:39)

实际上在最糟糕的情况下,第一个阵列将进行 n 比较,第二个 2n ,第三个 3n 很快直到(k - 1)n 所以现在复杂性变得简单

n + 2n + 3n + 4n + ... + (k - 1)n
= n(1 + 2 + 3 + 4 + ... + (k - 1))
= n((k - 1)*k) / 2
= n(k^2 - k) / 2
= O(nk ^ 2)

: - )

答案 2 :(得分:15)

这个怎么样:

第1步: 合并数组(1和2),数组(3和4)等。 (k / 2阵列合并2n,总工作量)。

第2步: 合并数组(1,2和3,4),数组(5,6和7,8)等等(k / 4合并4n,总工作量)。

第3步: 重复...

会有log(k)这样的“Steps”,每个都有kn工作。因此,完成的工作总数= O(k.n.log(k))。

即便如此,如果我们只是对数组的所有元素进行排序,我们仍然可以在O(k.n.log(k.n))时间内合并所有元素。

答案 3 :(得分:6)

我不同意其他答案。您不必每次比较1到1的项目。 您应该只是在排序集中维护最新的K项。  您删除最小的并通过其下一个元素重新发送它。这应该是n.log(k)

相关article。免责声明:我参与了写作

答案 4 :(得分:6)

  

k-way merge是一种算法,它采用大小为n的输入k排序数组。它输出所有元素的单个排序数组。

     

我原以为这个算法是O(kn)

我们可以通过矛盾反驳这一点。为使用您的算法的m个项目定义排序算法,其中k = m且n = 1。根据该假设,排序算法在O(m)时间内成功。矛盾,众所周知,任何排序算法的最坏情况至少为O(m log m)。

答案 5 :(得分:3)

一个常见的实现为k个排序的数组{i_1,i_2,i__k}中的每一个保留一个索引数组。在每次迭代时,算法从所有k个数组中找到最小的下一个元素并将其存储在输出数组中。由于您每次迭代都在进行kn迭代并扫描k个数组,因此总复杂度为O(k ^ 2 * n)。

这是一些伪代码:

Input: A[j] j = 1..k : k sorted arrays each of length n
Output: B : Sorted array of length kn

// Initialize array of indexes
I[j] = 0 for j = 1..k

q = 0

while (q < kn):
    p = argmin({A[j][I[j]]}) j = 1..k           // Get the array for which the next unprocessed element is minimal (ignores arrays for which I[j] > n)
    B[q] = A[p][I[p]]
    I[p] = I[p] + 1
    q = q + 1

答案 6 :(得分:3)

1)你有k个排序的数组,每个数组大小为n。因此,元素总数= k * n

2)获取所有k个数组的第一个元素并创建一个序列。然后找到这个序列的最小值。此最小值存储在输出数组中。找到k个元素的最小值的比较次数是k-1。

3)因此比较总数
   =(比较/元素)*元素数量
   =(k - 1)* k * n
   = k ^ 2 * n //大约是

答案 7 :(得分:0)

  1. 你有k个数组,每个数组都有n个元素。这意味着总共k * n个元素。

  2. 将其视为k * n的矩阵。要将第一个元素添加到merged / final数组,需要比较k个数组的头部。这意味着对于最终数组中的一个元素,您需要进行k次比较。

  3. 因此,从1和2开始,对于K n个元素,所用的总时间为O(k k * n)。

答案 8 :(得分:0)

对于那些想了解详细信息或需要帮助的人,我将扩展Recurse的answer和后续评论

  • 我们只需要k-1合并,因为最后一个数组未与任何内容合并
  • 用于将算术序列的各项相加的公式很有帮助; Sn=n(a1 + an)2

逐步完成k数组与n元素的前4次合并

+-------+-------------------+-------------+
| Merge | Size of new array |    Note     |
+-------+-------------------+-------------+
| 1     | n+n  = 2n         | first merge  |
| 2     | 2n+n = 3n         |             |
| 3     | 3n+n = 4n         |             |
| 4     | 4n+n = 5n         |             |
| k-1   | (k-1)n+n = kn     | last merge  |
+-------+-------------------+-------------+

要找到平均大小,我们需要将所有大小相加并除以合并数(k-1)。使用公式将前n个词Sn=n(a1 + an)2相加,我们只需要 first last 个词:

  • a1 = 2n(第一学期)
  • 一个 = kn(上学期)

我们要对所有术语求和,所以n=k-1(我们拥有的术语数)。插入数字,我们得到所有项之和的公式

Sn = ( (k-1)(2n+kn) )/2

但是,要找到平均大小,我们必须除以项数(k-1)。这样就消除了分子中的k-1,剩下的平均大小为

(2n + kn)/2

现在我们有了平均大小,我们可以将其乘以合并次数,即k-1。为了使乘法更容易,请忽略/2,而只需乘分子:

  (k-1)(2n+kn)
= (k^2)n + kn - 2n

在这一点上,您可以重新引入/2,但是没有必要,因为很明显,主导术语是(k^2)*n