基于元素间比较的排序算法中,快速排序、归并排序、堆排序是常见的时间代价为O(nlogn)的排序算法,它们都是《算法导论》第8章给出证明,“对于n个元素的输入序列,任何比较排序在最坏情况下都要用Big Omega(nlogn)次比较进行排序”。因此,归并排序和堆排序都是渐近最优的(下界为nlogn),快速排序最坏情况时间代价为O(n^2)。
非比较的三种算法:计数排序、基数排序和桶排序,对输入序列有一定的要求,可以实现线性时间代价O(n)的排序。
- 计数排序(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 result
if __name__ == '__main__':
A = [4, 0, 4, 3, 6, 1, 7, 6, 5]
print counting_sort(A, 7)
- 基数排序(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
- 桶排序(bucket_sort)
桶排序要求输入数字服从均匀分布(如0到1区间的分布)。
基本原理:把区间[0, 1)划分成n个大小相同的子区间(bucket),将输入的n个数映射分配到n个桶。对每个桶内的元素排序,然后依次把各个桶的排序结果拼接起来。由于输入元素服从均匀分布,不会出现很多元素落到一个桶的情况。如图所示:

《算法导论》给出的伪代码:
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 sort
concatenate the lists B[0], B[1], ..., b[n - 1] in order
这篇博客探讨了三种能在线性时间O(n)内完成排序的算法:计数排序、基数排序和桶排序。这些非比较排序算法对输入序列有一定要求,如计数排序适用于0到k之间的整数,基数排序针对数字的数位进行排序,而桶排序则依赖于输入元素的均匀分布。通过理解这些算法的工作原理,可以在特定条件下实现高效的排序操作。
1万+

被折叠的 条评论
为什么被折叠?



