计数排序是假设输入的数据都是0到k之间的整数,如果给定的数据集是有限的,那么排序可以在线性事件内完成。但是深入计数排序后会发现,计数排序有它的局限性,需要额外的存储空间,事件复杂度为O(n),但是空间复杂度上升到了O(n+k),如果数据集中整数的范围拉的很大,但是中间都是空出来的,有很大一部分数字没有出现,那么就不能能计数排序了。
先给出计数排序的基本算法(来自算法导论):
COUNTING-SORT(A, B, k) 1 for i <- to k 2 do C[i] <- 0 3 for j <- 1 to length[A] 4 do C[A[j]] <- C[A[j]] + 1 5 for i <- 1 to k 6 do C[i] <- C[i] + C[i-1] 7 for j <- length[A] downto 1 8 do B[C[A[j]]] <- A[j] 9 C[A[j]] <- C[A[j]] - 1
在算法导论上有一个习题,就是如果把第7行的 j 的值从1开始到length[A],那么程序还能继续执行,问题是算法还稳定吗?根据上面的分析,如果有多个x值,那么从前向后遍历第一个找到的x值被放在了相对其他x值得最后,所以算法就不是稳定的了。
#include<stdio.h> #include<stdlib.h> #include<windows.h> void counting_sort(int *a, int *b, int len, int k) { int *record = (int*)malloc(sizeof(int) * (k+1)); int i; if(!record) return; memset(record, 0, sizeof(int)*(k+1)); for(i = 1; i <=len; i++) record[a[i]]++; for(i = 1; i <= k; i++) record[i] = record[i] +record[i-1]; for(i = len; i >= 1; i--) { b[record[a[i]]] = a[i]; record[a[i]]--; } } int get_max_val(int *a, int len) { int max = a[1]; int i; for(i = 2; i <= len; i++) if(a[i] > max) max = a[i]; return max; } void main() { int a[] = {0, 2, 5, 3, 0, 2, 3, 0, 3}; int len = sizeof(a)/sizeof(int); int max_val = 0; int *b = (int*)malloc(sizeof(int) * len); memset(b, 0, sizeof(int)*len); max_val = get_max_val(a, len-1); counting_sort(a, b, len-1, max_val); for(int i = 1; i < len; i++) { printf("%d\t", b[i]); } printf("\n"); }