MIT算法导论课程笔记5: 线性排序算法

课程网站:http://open.163.com/special/opencourse/algorithms.html

常见的merge sort, quick sort, insert sort, heap sort都是基于比较的排序算法,即通过比较元素的相对大小,确定排序顺序。这节课首先通过decision tree理论上证明了基于比较的排序算法的平均时间复杂度不会好于 O ( n log ⁡ n ) O(n\log n) O(nlogn);然后提出一种用空间换时间的counting sort线性排序算法;然后进一步提出了一种可以在时间、空间之间做tradeoff的线性排序算法,radix sort。值得注意的是,两种排序算法的线性时间复杂度论证都基于对元素值范围的限制,同时需要更多的额外空间,线性复杂度在理论上很漂亮,实际使用中却往往是快排更胜一筹。

比较排序算法的平均时间复杂度下限

基于比较的排序算法都可以理论上推导出等价的decision tree排序模型。具体地,decision tree排序模型为不同长度的序列分别建立一个决策树 D n D^n Dn,其中 n n n为序列长度,即元素个数。决策树的叶子节点(即最终的决策)即为排序后的顺序;每个internal node则用于指定在当前状态下,基于指定元素的比较结果,采取相应的动作(更新 状态/需要比较的元素)。

对于元素个数为 n n n的序列,对应的决策树模型/算法 D n D^n Dn需要至少 n ! n! n!个叶子节点(排序),才能对所有可能的序列进行排序。则决策树的深度最少为 O ( n log ⁡ n ) O(n\log n) O(nlogn),叶子节点的深度均值至少为 O ( n log ⁡ n ) O(n\log n) O(nlogn),从而论证的最差时间复杂度 和 平均时间复杂度 的下界都是 O ( n log ⁡ n ) O(n\log n) O(nlogn)

线性排序算法

counting sort

计数算法,简单地说,是先遍历序列,记录每个元素出现的个数;然后编列元素值范围,得到相应元素值对应的排序后位置;最后将元素放置到相应位置上。假设序列长度为 n n n,元素的可能取值为 k k k,时间复杂度为 O ( n + k ) O(n+k) O(n+k),需要 O ( k ) O(k) O(k)的空间用于排序, O ( n + k ) O(n+k) O(n+k)的额外空间用于稳定排序。

'''pythonic example codes'''

a = np.random.randint(low=0,high=1000,size=100) #building input array
count = [np.sum(a==i) for i in range(0,1000)] #counting 
count_cumsum = np.cumsum(count) - 1 #the position for each possible number
output = [None]*len(a)
for i in range(len(a)-1,-1,-1):
	output[count_cumsum[a[i]]] = a[i]
	count_cumsum[a[i]] -= 1
return output

此算法仅在元素范围 k k k较小的情况表现良好,因为是 O ( n + k ) O(n+k) O(n+k)的时间和空间复杂度。例如,若 k k k n n n较大,均无法存储于cache等快速访问空间,则多轮线性次数的内存访问操作,实际中仍然是慢于 O ( n log ⁡ n ) O(n\log n) O(nlogn)的排序算法的;同时额外空间也是巨大的开销。

radix sort

radix sort可以在空间和时间之间做tradeoff,一定程度上缓解了counting sort对 额外空间,以及对元素范围值 k k k 的需求与限制。

简单的理解,radix sort是逐位排序,第 m m m轮排序过后,保证每个元素的后 m m m位组成的数字顺序排列。第 m + 1 m+1 m+1轮仅对第 m + 1 m+1 m+1位做稳定排序,若两个元素 m + 1 m+1 m+1位数字不同,则 m + 1 m+1 m+1位数字较大的元素后 m + 1 m+1 m+1位组成数字仍然较大;若两个元素 m + 1 m+1 m+1位数字相同,基于稳定排序以及之间假设,排序后两者仍然是顺序排列;论证结束。

具体地,对于 b b b bit的整型序列,radix sort将排序拆成 b / r b/r b/r轮,其中 r r r为每轮排序使用的bit数目。从least signficant的 r r r bit开始,每一轮都对相应 r r r bit组成数字 对应的序列进行稳定排序。 r r r轮过后,最终得到整个 b b b bit的整型序列的稳定排序。

时间复杂度是 O ( b r ( n + 2 r ) ) O(\frac b r(n+2^r)) O(rb(n+2r)),空间复杂度为 O ( n + 2 r ) O(n+2^r) O(n+2r)。这里的稳定排序算法采用了counting sort。

时间复杂度的一个上界是 O ( b n / log ⁡ n ) O(bn/\log n) O(bn/logn)(令 r = log ⁡ n r=\log n r=logn),从而只要 b ∼ log ⁡ n b\sim \log n blogn,最差时间复杂度都是线性的。相比于counting sort中要求 k = O ( n ) k=O(n) k=O(n),radix sort要求 k = 2 b − 1 = n d k=2^b-1 = n^d k=2b1=nd(其中 d d d为任意常数)。即radix sort通过牺牲时间,放松了对元素值范围的限制,减少了空间复杂度。

你可能感兴趣的:(MIT算法导论)