为什么合并sorting最差情况运行时间O(n log n)?
有人能用简单的英语给我解释一下吗?还是一个简单的解释方法?
在“传统”合并sorting中,每次通过数据都会使sorting的子部分的大小加倍。 第一遍之后,该文件将被分为两部分。 第二次通过后,长度为四。 然后是八,十六,等等文件的大小。
有必要保持加倍sorting部分的大小,直到有一个部分组成整个文件。 这将需要lg(N)的段大小加倍以达到文件大小,并且数据的每次通过将花费与logging数量成正比的时间。
合并sorting使用分而治之的方法来解决sorting问题。 首先,它使用recursion将input分为一半。 分割之后,对半部分进行sorting并将它们合并为一个sorting的输出。 看到图
这意味着最好先sorting一半,然后做一个简单的合并子程序。 因此了解合并子程序的复杂性以及在recursion中调用多less次是非常重要的。
合并sorting的伪代码非常简单。
# C = output [length = N] # A 1st sorted half [N/2] # B 2nd sorted half [N/2] i = j = 1 for k = 1 to n if A[i] < B[j] C[k] = A[i] i++ else C[k] = B[j] j++
很容易看出,在每一个循环中,你将有4个操作: k ++ , i ++或j ++ , if语句和属性C = A | B。 所以你将会有less于或等于4N + 2的操作给出一个O(N)的复杂度。 为了certificate4N + 2将被视为6N,因为对于N = 1( 4N + 2 <= 6N )是正确的。
所以假设你有一个N个元素的input,并且假设N是2的幂。在每一个级别你都有两倍多的子问题,input中有来自前一个input的一半元素。 这意味着在水平j = 0,1,2,…,lgN将有2 ^ j个子长度为N / 2 ^ j的input。 每个级别j的操作次数将小于或等于
2 ^ j * 6(N / 2 ^ j)= 6N
注意不pipe你的水平总是less于或者等于6N的水平。
由于有lgN + 1级,所以复杂度会很高
O(6N *(lgN + 1))= 0(6N * lgN + 6N)= 0 (n lgN)
参考文献:
- Coursera课程algorithm:devise和分析,第1部分
这是因为不pipe是最坏情况还是平均情况,合并sorting在每个阶段将数组分成两部分,每个阶段给出lg(n)分量,另一个N分量来自在每个阶段进行的比较。 所以把它合并成几乎是O(nlg n)。 无论是平均情况还是最坏情况,lg(n)因子总是存在的。 其余N因素取决于在两种情况下进行的比较所做的比较。 现在最坏的情况是在每个阶段对N个input进行N次比较。 所以它变成了O(nlg n)。
在将数组分解到您有单个元素的阶段(即将其称为子列表)之后,
-
在每个阶段,我们将每个子列表的元素与其相邻的子列表进行比较。 例如,[重用@ Davi的图片]
- 在阶段1中,每个元素都与其相邻的元素进行比较,所以n / 2比较。
- 在阶段2中,子列表的每个元素都与其相邻子列表进行比较,因为每个子列表都被sorting,这意味着两个子列表之间的最大比较次数是<=子列表的长度,即2(在阶段2)和在第三阶段和第四阶段的4次比较,因为次级名单的长度增加了一倍。 这意味着每个阶段的最大比较次数=(子列表长度*(子列表数量/ 2))==> n / 2
- 正如你所观察到的阶段的总数将是'log(n)'所以总的复杂性将是== (每个阶段的最大比较数*阶段数)== O((n / 2)* log (n))==> O(nlog(n))
MergeSortalgorithm需要三个步骤:
- 除法步骤计算子arrays的中间位置,并且需要恒定的时间O(1)。
- 征服步骤recursion地对每个大约n / 2个元素的两个子数组进行sorting。
- 组合步骤在每次通过时合并总共n个元素,最多需要n次比较,因此需要O(n)。
该algorithm需要近似logn遍来对n个元素的数组进行sorting,因此总的时间复杂度为nlogn。