任何比较排序在最坏情况下要经过Ω(nlgn)次比较。而计数排序,基数排序和桶排序可以突破这个下界,因为它们不是比较来确定排序顺序的。
1. 计数排序
计数排序假设n个输入元素中的每一个都是在0到k区间内的一个整数,其中k为某个整数。当k
= O(n)时,排序的运行时间是Θ(n)。
假设输入是一个数组A[1..n],A.length =
n.我们还需要两个数组:B[1..n]存放排序的输出,C[0..k]提供临时存储空间。
伪代码:
在10到12行的循环部分,把每个元素A[j]放到它在输出数组B中的正确位置上。总的时间代价是Θ(k + n),实际工作中当k = O(n)时,一般采用计数排序,运行时间为Θ(n).
计数排序是稳定的,即具有相同值的元素在输出数组中的相对次序与它们在输入数组中的相对次序相同。注意在第10行j要从A.length迭代到1而不能反过来。
2. 基数排序
基数排序可以对n个d位数进行排序,是按最低有效位进行排序的。如图:
伪代码:
给定n个d位数,其中每一个数位有k个可能的取值。如果RADIX-SORT使用的稳定排序方法耗时Θ(n + k),如计数排序,那么它就可以在
Θ(d(n + k))时间内将这些数排好序。
给定一个b位数和任何正整数r <=
b,如果RADIX-SORT使用的稳定排序算法对数据取值区间是0到k的输入进行排序耗时Θ(n + k),那么它就可以在Θ((b / r)(n + 2 ^ r))时间内将这些数排序。
这里指将b位数看做d = b / r个r位数。每个数是0到2 ^ r -
1区间内的一个整数,用计数排序时间为Θ(n + 2 ^
r).所以总排序时间是
Θ((b / r)(n + 2 ^ r))。我们希望取到r使表达式的值最小。如果,则任意r <= b都有(n + 2 ^ r) = Θ(n).显然选择r = b可以得到时间代价为(b / b)(n + 2 ^ b) = Θ(n). 如果,选择可以得到运行时间为Θ(bn / lgn).
3. 桶排序
桶排序假设输入数据服从均匀分布,平均情况下时间代价为O(n).
桶排序将[0,1)区间划分为n个相同大小的子区间,或称为桶。然后将n个输入数分别放到各个桶中。为了得到输出结果,先对每个桶中的数进行排序,然后遍历每个桶,按照次序把各个桶中的数据列出来即可。
假设输入是一个包含n个元素的数组A,且每个元素A[i]满足0 <= A[i] <
1,此外,还要一个临时数组B[0..n - 1]来存放链表(即桶)。
伪代码: