Insertion Sort & Merge sort

---

Insertion sort

Attempt#1

每次将元素A[j]插入它之前的有序序列A[1 .. j-1]中,插入方式是与前一个相邻元素两两比较并交换直到到达正确位置

image-20210508163831891

Complexity

显然复杂度主要来自于 compare 和 swap :

平均情况下,比较和交换均需要 Θ(n2),虽然可以通过binary search将比较部分改进为 Θ(nlogn),但由于交换采用相邻元素两两交换的方式,整个算法复杂度仍然为 Θ(n2 + nlogn)= Θ(n2)

下面考虑另一种排序方式:归并排序

Merge sort

Algo

image-20210508211213518

=== devide&conquer ===

将数组A一分为二得到数组L和R

将L和R排序得到L‘和R’

合并L‘和R’得到排序后的数组A‘

递归执行...

image-20210508192751631

方法merge(Elem[] L', Elem[] R')应接收两个已排序的数组 L’ 和 R‘

“合并”的过程需要设置两个工作指针,分别指向L’和R‘中待处理的元素,每确定一个元素位置则将指针向后移一位

image-20210508193019318

merge的复杂度取决于工作指针的移动次数,假如某个数组(不妨以R’为例)的所有元素都比左边的最小值小,则左边数组工作指针不会移动,直到右侧工作指针扫描完整个R’。此时只需将左侧数组直接”连接“到R‘后即可得到结果,总共耗费 Θ(n/2)。

最坏的情况可见是左右工作指针交替移动直到遍历完所有元素,这时的时间复杂度为Θ(n)。

Complexity

设对长度为n的数组进行归并排序的时间复杂度为T(n),不难得出下列递推关系:
$$
T(n) = C_1 + 2.T(n/2) + C.n
$$
C1表示devide需要常数时间,C.n表示merge需要Θ(n),T(n/2)为对子数组归并排序(recursion)的耗时

现在来求解上面的递归式(recurrence solving):

因为有C.n在可以忽略常数项C1,即有
$$
T(n) = 2.T(n/2) + C.n
$$
从确定项C.n开始展开,T(n) = C.n + 2.T(n/2) = C.n + ( 2.( C.n/2 + 2(C.n/4 + T(n/4)) ) ) = ...

recursive tree如下:

image-20210508201823776

可见全部展开后T(n)就等于所有结点值的和
$$
T(n) = (1+log_2n).C.n = Θ(nlgn)
$$

Auxiliary space

现在考虑 merge sort 的空间复杂度,由于 merge() 需要接收两个有序数组 L’ 和 R‘ ,因此需要2*n/2 = n的辅助空间存放排序后的子数组 L’ 和 R‘,空间复杂度为 Θ(n)

可以看出 insertion sort 虽然在时间复杂度上表现不如 merge sort,但却在空间复杂度上却略胜一筹,其仅需要一个变量 temp 来辅助元素的两两交换,其空间复杂度为 Θ(1),我们称其为 原地工作

Tree for different recurrence

使用递归树可以更容易地看出算法所需时间 T(n),假设如下两个递归式,求算法的时间复杂度:

#1

image-20210508213840842

计算过程
$$
T(n) = C(1+2+4+\ ...\ +n/2+n ) = Cn(1+1/2+1/4+...)=Θ(n)
$$

#2

image-20210508213947470

计算过程:
$$
T(n) = Cn2(1+1/2+1/4+...)=Θ(n2)
$$

posted @ 2021-05-08 21:48  盐盐盐の锅  阅读(87)  评论(0编辑  收藏  举报