最近在学习 MIT 的算法课:Introduction to Algorihtms
地址在这里,打算对着《CLRS》把这门课跟完
顺手写一些笔记,放在这里,以供日后复习查阅
这一篇文章对应的是6.006中 Lecture 3 的内容
包括了 Insertion Sort & Merge Sort
下面就来一一分析
Insertion Sort
For i = 1, 2, …., n
Insert A[i] into sorted array A[0 : n - 1]
by pairwise swaps down to the correct position
Image Source:
http://interactivepython.org/courselib/static/pythonds/SortSearch/TheInsertionSort.html
这里要向大家推荐一个很好用的算法可视化网站:https://visualgo.net/en
里面有常用的数据结构和算法,并以动画的形式展现出来
对于 Insertion Sort,这里给出了它的伪代码
Java 实现如下
下面来稍微分析一下这个算法
我们从 array 的第二项开始,即把 array1 当成 key
一直遍历到 array[n - 1],一共有 n - 1 项, 即θ(n)
对每一项来说,最坏情况是它比前面已经 sort 好了的 element 都要小
即与前面的每一项都要进行 compare & swap,也为 θ(n)
时间复杂为 O(n^2)
注意上面我们所说的这个步骤:compare & swap
, 如果 compare
的时间花费远大于 swap
那么我们要思考有没有一种方式来减少 compare 的时间花费?
答案是 binary search,对于每个 key,在前面已经 sorted 的 array 里用 binary search
这样可以把时间复杂度降为 O(nlgn)
注意这里所说的 O(nlgn) 是对 compare 来说的
swap 仍然花费 O(n^2), 因为在数组这种数据结构里,元素是相邻的
Merge Sort
Merge Sort 体现了 Divide & Conqure 的思想
Image Source: http://www.geeksforgeeks.org/merge-sort/
Merge Sort 可视化演示:https://visualgo.net/en/sorting
Merge Sort 的伪代码:
Java 代码实现如下
下面我们来分析一下这个代码,把关注点放在时间和空间的话费上
首先我们可以根据整个流程分析出以下式子:T(n) = C1 + T(n/2) + cn
C1
is Divide time, cn
is Merge time
Image Source: https://www2.hawaii.edu/~janst/311/Notes/Topic-02.html
对这个树来说,高度为 1 + lgn, 一共有 n leaves
每一层花费的时间都是 cn
所以总时间是 T(n) = (1 + lgn) * cn, 即θ(nlgn)
空间方面:Auxiliary Space: O(n)
Merge Sort vs Insertion Sort
虽然 Merge Sort 花费 O(nlgn) 时间,而 Insertion Sort 花费 O(n^2)
但在常数 c 上两者还是有很大区别的
事实上,在 Python 中,Merge Sort Running Time:2.2 nlgn
Insertion Sort Running Time: 0.2n^2
可见,当 n 较小时,用 Insertion Sort 是比较好的选择