《算法导论》线性时间O(n)排序

来源:互联网 发布:手机逛淘宝费流量吗 编辑:程序博客网 时间:2024/05/19 03:28

基于元素间比较的排序算法中,快速排序、归并排序、堆排序是常见的时间代价为O(nlogn)的排序算法,它们都是《算法导论》第8章给出证明,“对于n个元素的输入序列,任何比较排序在最坏情况下都要用Big Omega(nlogn)次比较进行排序”。因此,归并排序和堆排序都是渐近最优的(下界为nlogn),快速排序最坏情况时间代价为O(n^2)。

非比较的三种算法:计数排序、基数排序和桶排序,对输入序列有一定的要求,可以实现线性时间代价O(n)的排序。

  1. 计数排序(counting_sort)

要求输入的n个数为介于0到k之间的整数,当k=O(n)时,计数排序的运行时间为Big Theta(n)。

基本原理是:对每一个输入元素x,统计出小于x的元素个数c,那么可以把x放置到第c+1的位置。

def counting_sort(A, k):    count = [0]*(k + 1)    result = [0] * len(A)    for j in xrange(len(A)):        count[A[j]] += 1    for i in xrange(1, k + 1):        count[i] += count[i - 1]    for j in xrange(len(A) - 1, -1, -1):        result[count[A[j]] - 1] = A[j] # Remember '- 1'        count[A[j]] -= 1    return resultif __name__ == '__main__':    A = [4, 0, 4, 3, 6, 1, 7, 6, 5]    print counting_sort(A, 7)
  1. 基数排序(radix_sort)

基数排序是对数字,逐个数位,从低到高排序(如先排个位,然后排十位)。如图所示:

radix_sort

伪代码如下:

RADIX-SORT(A, d)"""each element has d digits"""for i = 1 to d do    use stable sort to sort A on digit i
  1. 桶排序(bucket_sort)

桶排序要求输入数字服从均匀分布(如0到1区间的分布)。

基本原理:把区间[0, 1)划分成n个大小相同的子区间(bucket),将输入的n个数映射分配到n个桶。对每个桶内的元素排序,然后依次把各个桶的排序结果拼接起来。由于输入元素服从均匀分布,不会出现很多元素落到一个桶的情况。如图所示:

bucket_sort

《算法导论》给出的伪代码:

BUCKET-SORT(A)n = length(A)for i = 1 to n do    insert A[i] into list B[floor(n*A[i])]for i = 0 to n - 1 do    sort list B[i] with insertion sortconcatenate the lists B[0], B[1], ..., b[n - 1] in order
0 0