算法导论8-2
读书笔记
本小节介绍了计数排序,计数排序的基本思想是:
对每个输入元素\(x\),确定小于\(x\)的元素个数。利用这一信息,就可以直接把\(x\)放到它在的输出数组中的位置上了。
所以这里的重点是如何确定小于\(x\)的元素个数,这里引入了一个数组\(C\),\(C\)的长度为\(k\),\(k\)的值要大于等于输入数组中的最大值;数组\(C\)的下标存储输入数组的值,而下标所对应的值存储小于等于该下标的数的个数;接下来就可以获得排好序的输出数组;
伪代码如下:
COUNT-SORT(A, B, k)
let C[0..k] be a new array
for i = 0 to k
C[i] = 0
for j = 1 to A.length
C[A[j]] = C[A[j]] + 1
// C[i] now contains the number of elements to i
for i = 1 to k
C[i] = C[i] + C[i-1]
// C[i] now contains the number of elements less than or equal to i
for j = A.length downto 1
B[C[A[j]]] = A[j]
C[A[j]] = C[A[j]] - 1
更加详细的过程请查阅书籍;
优点
- 计数排序没有采取比较的操作,所以在运行时间上要更优,为\(\theta(n)\)。
- 具有相同值的元素在输出数组中的相对次序与它们在输入数组中的相对次序相同。
缺点
- 采用了用空间换时间,所以对内存消耗甚巨;
- 只适用于正整数数组作为输入数组,泛用性太低
- 需要事先确定\(k\)的值,对输入数组有要求
课后习题
8.2-1
参照图8-2的方法,说明\(COUNTING-SORT\)在数组\(A=<6,0,2,0,1,3,4,6,1,3,2>\)上的操作过程。
略。
8.2-2
试证明\(COUNTING-SORT\)是稳定的。
观察伪代码的最后一个循环,从输入数组的最后一个元素开始倒序赋值,\(C[A[j]]\)会随着不断赋值而减小,同样保持了次序;
8.2-3
假设我们在\(COUNTING-SORT\)的第\(10\)行循环的开始部分,将代码改写为:
for j = 1 to A.length
试证明该算法仍然正确。它还稳定吗?
关于正确性的证明,略。
不稳定了,相对次序倒置;
8.2-4
设计一个算法,它能够对于任何给定的介于\(0\)到\(k\)之间的\(n\)个整数先进行预先处理,然后在\(O(1)\)时间内回答输入的\(n\)个整数中有多少个落在区间\([a..b]\)内。你设计的算法的预处理时间应为\(\theta(n+k)\)。
算法和计数排序是一致的,区别在于最后一步:\(C[b]-C[a-1]\)