《算法导论》笔记 第8章 8.2计数排序
【笔记】
计数排序假设n个输入元素中的每一个都是介于0到k之间的整数,此处k为某个整数。当k=O(n)时,计数排序的运行时间为 Θ(n)。
计数排序是稳定的。
void countingSort(int A[],int B[],int n,int k) { int C[MAXK]; for (int i=0;i<=k;i++) { C[i] = 0; } for (int j=1;j<=n;j++) { C[A[j]]++; } for (int i=1;i<=k;i++) { C[i] = C[i] + C[i-1]; } for (int j=n;j>=1;j--) { B[C[A[j]]] = A[j]; C[A[j]]--; } }
【练习】
8.2-1 说明COUNTING-SORT在数组 A = <6,0,2,0,1,3,4,6,1,3,2> 上的处理过程。
C = <2,2,2,2,1,0,2>
C = <2,4,6,8,9,9,11>
C[i]表示最后一个值为i的元素应在的位置。
倒序将A[i]中的元素复制到B[i]中的目标位置。
8.2-2 证明 COUNTING-SORT 是稳定的。
对最后的一次循环应用循环不变式证明B数组是稳定的。
初始化:在第一次迭代前,B中没有元素,是稳定的。
保持:某次迭代中,C[i]数组中,存储的是A中小于等于i的数有多少个。
即表示小于等于A[j]的最后一个元素,应在的位置,将A[j]放入B中后,C[A[j]]--。
此时,之后的值为A[j]的元素数减去一。所以j之前的与j相同的数不会放到A[j]之后,因此A[j..n]仍是稳定的。
终止:最后一次迭代后,所有元素都复制到了B中,因此B[1..n]是稳定的。
8.2-3 在 COUNTING-SORT 过程中,假设最后一次循环的fao首部改为 for j <- 1 to length[A],证明该算法仍能正常工作。修改后的算法是稳定的吗?
在每次循环中A[j]被放到小于等于A[j]的最后一个元素所在的位置,而A[j]不一定是最后一个小于等于A[j]的元素,但一定等于A[j]。
因此该算法仍能正常工作,却不再稳定。
8.2-4 请给出一个算法,使之对于给定的介于0到k之间的n个整数进行预处理,并能在O(1)时间内,回答出输入的整数中有多少个落在区间[a..b]内。你给出的算法的预处理的时间应该是Θ(n+k)。
void prepare(int A[],int C[],int n,int k) { for (int i=0;i<=k;i++) { C[i] = 0; } for (int j=1;j<=n;j++) { C[A[j]]++; } for (int i=1;i<=k;i++) { C[i] = C[i] + C[i-1]; } } int getAns(int C[],int L,int R) { if (L==0) return C[R]; return C[R]-C[L-1]; }
查询时应保证0<=L<=R<=k。