链表上合并排序的运行时间?

Posted

技术标签:

【中文标题】链表上合并排序的运行时间?【英文标题】:Running time of merge sort on linked lists? 【发布时间】:2014-05-23 16:25:19 【问题描述】:

我遇到了这段代码来对链接列表执行合并排序.. 作者声称它运行时间为 O(nlog n).. 这是它的链接... http://www.geeksforgeeks.org/merge-sort-for-linked-list/ 我的主张是它至少需要 O(n^2) 时间……这是我的论点…… 看,你划分列表(无论是数组还是链表),记录 n 次(参考递归树),在每个分区期间,给定一个大小为 i=n,n/2,...,n/2^ 的列表k,我们将花费 O(i) 时间来划分原始/已经划分的列表。由于 sigma O(i)= O(n),我们可以说,对于任何给定的调用,我们需要 O(n) 时间来划分分区(草率),因此考虑到执行单个分区所需的时间,现在出现的问题是总共会发生多少个分区,我们观察到每个级别 i 的分区数等于 2^i ,所以求和 2^0+2^1+....+2^(lg n ) 给我们 [2(lg n)-1] 作为简化的总和,这只是 (n-1) ,这意味着我们称分区 n-1,(让我们将其近似为 n),时间如此,复杂度至少是 n^2 的大欧米伽。 如果我错了,请告诉我在哪里...谢谢:)

然后经过一些回顾,我将 master 方法应用于递归关系,其中我将用于数组上的传统合并排序的 1 替换为这种类型的合并排序的 n 的 theta(因为除法和组合操作每次取 n 次的 theta),运行时间原来是 (n lg n) 的 theta... 我还注意到每个级别的成本是 n(因为 2 power i * (n/(2pow i)))...是每个级别所花费的时间...所以它在每个级别的 n 的 theta * lg n水平..暗示它的θ(n lg n)......我只是解决了我自己的问题吗??请帮助我自己有点困惑......

【问题讨论】:

合并两个链表可以在 O(n) 的运行时间内完成。对这些中的每一个进行排序将花费 O (N log N) 在递归树的每一层,你都做 O(n) 的工作。有 O(log n) 个级别。 Q.E.D 【参考方案1】:

大小为 n 的输入列表的递归复杂度定义为

T(n) = O(n) + 2 * T(n / 2)

展开我们得到:

T(n) = O(n) + 2 * (O(n / 2) + 2 * T(n / 4))
     = O(n) + O(n) + 4 * T(n / 4)

再次展开我们得到:

T(n) = O(n) + O(n) + O(n) + 8 * T(n / 8)

显然这里有一个模式。因为我们可以精确地重复这个扩展 O(log n) 次,所以我们有

T(n) = O(n) + O(n) + ... + O(n)   (O(log n) terms)
     = O(n log n)

【讨论】:

对于这种特殊情况,这是直观掌握master theorem 的好方法 :) 该论点也可用于简单的归纳证明【参考方案2】:

出于某种奇怪的原因,您执行了两次求和。

要拆分和合并大小为 n 的链表,需要 O(n) 时间。递归深度为 O(log n)

您的论点是拆分步骤需要 O(i) 时间并且拆分步骤的总和变为 O(n) 然后您将其称为仅执行一次拆分所花费的时间。

相反,让我们考虑一下,一个大小为 n 的问题形成两个 n/2 问题,四个 n/4 问题,八个 n/8 等等,直到形成 2^log n n/2^logn 子问题。总结这些你得到 O(nlogn) 来执行拆分。 另一个 O(nlogn) 来组合子问题。

【讨论】:

以上是关于链表上合并排序的运行时间?的主要内容,如果未能解决你的问题,请参考以下文章

在C中排序链表[关闭]

合并两个排序的链表使之依然有序(不开辟新空间在原链表上操作的非递归版本)

在编写合并两个排序链表的代码时获取地址错误的运行时负载

Leetcode练习(Python):链表类:第23题:合并K个排序链表:合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

leetcode23.合并K个排序链表

java牛客BM4.合并两个排序的链表 BM5. 合并k个已排序的链表