三种最基本的线性排序算法
计数排序
计数排序是假设数组A中的元素都是在0到K区间内的整数。构建一个数组C[0,..,k]初始化为-1,如果数组A中的元素互异的话,那么把A的元素拷贝到C中:C[A[i]] = A[i],然后遍历C,把非-1的元素依次拷贝到数组A中即可完成排序。但数组有元素相等要怎么处理了。
元素互异的做法,还可以是C[0,..,k]初始化为0,使C[A[i]] = 1,然后遍历C如果C[i]等于1,就把下标i依次放到A中,这样好像更好。如果有相同的元素,也就是会有C[A[i]] > 1,把下标i连续在A中放入C[A[i]]就行了。
伪代码
COUNTING-SORT(A)
let C[0..k] be a new array
for i=0 to k
c[i] = 0
for i=1 to A.length
C[A[i]] = C[A[i]] + 1
j = 1
for i=0 to k
while c[i] >= 1
A[j] = i
j = j + 1
c[i] = c[i] - 1
对于整数串排序很显然可以得到正确的结果。
上述过程显然只能存粹的排序一个整数串,不能推广到一般化,不能排序数据记录或对象,当一组对象某个属性可以用0到k的整数表示时,则我们可以基于这个属性对对象排序,使用计数排序来排序数组,上面的过程就是错误的。
这里我们依然要假设A[i]表示元素,表示对象,同时A[i]表示某个属性的值且是0到k区间的整数。
先定义一个数组B来存放输出结果,B.length=A.length,当然也可以在数组A上移动元素的位置来排序,但不适合计数排序方法。
思路是通过A[i]的值对应C[0,..,k]中的值来确定放在B[?]的位置,A[i]对应C的下标,如何确定C[A[i]]值,然后通过C[A[i]]的值来确定B[?]的下标?
显然B[?]的下标就是C[A[i]]或者C[A[i]]的表达式。然是如果2个相同的A[i]值,就不好处理了。
可以猜想如果B是A排好序的数组,那么B的下标j就是表示小于数组中元素小于等于B[j]的个数
那么C[A[i]]的值如果==小于等于A[i]值的个数
则B[C[A[i]]] = A[i]就是把A[i]放到排好序对应的位置。
如何计数C[A[i]]
for i=1 to A.length
C[A[i]] = C[A[i]] + 1
//到这里只是算出了C[A[i]]的值==等于A[i]值的个数
//把小于A[i]值的个数也加上
for j=1 to k
C[j] = C[j-1] + C[j]
计算B[C[A[i]]] = A[i]
for i=1 to A.length
B[C[A[i]]] = A[i]//如果i后面有相同的值会覆盖之前的,C[A[i]]可以减去1来解决
C[A[i]] = C[A[i]] - 1
这里有一个问题就是相同的值A[i]和A[j],i
for i = A.length to 1
B[C[A[i]]] = A[i]
C[A[i]] = C[A[i]] - 1
显然是的。
合并一下,完整代码如下:
COUNTING-SORT(A,B,k)
let C[0..k] be a new array
for i=0 to k
c[i] = 0
for i=1 to A.length
C[A[i]] = C[A[i]] + 1
//到这里只是算出了C[A[i]]的值==等于A[i]值的个数
//把小于A[i]值的个数也加上
for j=1 to k
C[j] = C[j-1] + C[j]
for i = A.length downto 1
B[C[A[i]]] = A[i]
C[A[i]] = C[A[i]] - 1