计数排序并非一种基于比较进行的排序,它是计算一个序列中的值在正常排好序中的序列所处的位置,怎么求解一个数的位置呢?就是利用下脚标进行求解,新建一个数组resu[],数组的长度要比序列中的最大值大1,数组中的值全部初始化为0,然后遍历原序列,将原序列的值i作为新建数组resu[]的下脚表,对resu[i]++操作,这样就得出值 i 出现的次数;然后再利用resu[i]=resu[i]+resu[i-1]求解出i在原序列中的位置。
计数排序需要两个额外的数组作辅助,提供临时存储的resu数组,存放最终排序结果的sorted_array数组,算法描述如下:
counting_sort(array,sorted_array)//
1、for i = 0 to max //max为array中的最大值
2、 resu[i]=0;
3、for j= 1 to length(array)
4、 resu[array[j]]=resu[array[j]]+1 //求出包含array[i]的个数
5、for i=min+1 to max //min为array中的最小值
6、 resu[i]=resu[i]+resu[i-1] // i 在序列中的位置
7、for j=length(array) downto 1
8、 sorted_array[resu[array[j]]] = array[j]
//如果arr[i]==arr[i-1]的话,显然要将arr[i-1]放到arr[i]之前
//所以要进行resu[arr[i]]--操作
9、 resu[array[j]] = resu[array[j]]-1
以序列 2 5 3 1 2 3 1 3 为例,下图是实现该算法的排序过程
根据算法描述,可以写出如下程序:
public class my{ public static void main(String[] args)throws InterruptedException{ int arr[]={2,5,3,2,2,3,2,1,3,9}; int[] sorted_array=new int[arr.length]; int max=arr[0],i=0,min=arr[0]; //求出最小值和最大值 for(int val:arr){ max=max<val?val:max; min=min>val?val:min; } System.out.println("min = "+min); int[] resu=new int[max+1]; for(int val:arr){ resu[val]++; } for(i=min+1;i<=max;i++){ resu[i]=resu[i]+resu[i-1]; } for(i=arr.length-1;i>=0;i--){ sorted_array[resu[arr[i]]-1]=arr[i]; //如果arr[i]==arr[i-1]的话,显然要将arr[i-1]放到arr[i]之前 //所以要进行resu[arr[i]]--操作 resu[arr[i]]--; } System.out.println(); printArray(arr); printArray(sorted_array); } static void printArray(int[] array){ for(int val:array){ System.out.print(val+" "); } System.out.println(); } }
可以看出,计数排序的时间复杂度是O(n),但空间复杂度是O(n),而且如果序列中的最大值如果远远大于序列长度的话,这种排序是很不划算的,因为空间浪费太大,但是对于给定范围0到k之间的数进行排序的话,效率还是挺高的,尤其是n非常大的情况下。