“计数排序只能用在数据范围不大的场景中,如果数据范围 k 比要排序的数据 n 大很多,就不适合用计数排序了。而且,计数排序只能给非负整数排序,如果要排序的数据是其他类型的,要将其在不改变相对大小的情况下,转化为非负整数。比如,还是拿考生这个例子。如果考生成绩精确到小数后一位,我们就需要将所有的分数都先乘以 10,转化成整数,然后再放到 9010 个桶内。再比如,如果要排序的数据中有负数,数据的范围是[-1000, 1000],那我们就需要先对每个数据都加 1000,转化成非负整数。”
package data.sort.line;
public class CountSort {
public static int[] countSort(int b[]) {
int maxSize=b[0];
int c[]=new int[b.length];
//1)找出数据中的最大数
for(int i=1;i<b.length;i++) {
if(b[i]>maxSize) {
maxSize=b[i];
}
}
//确定桶的数量,创建一个maxSize+1的桶数组,桶下标代表数值,桶中存放值代表重复数据的数量
int bubble[]=new int[maxSize+1];
//2)把值相等的数据放入到同一个桶中,统计每个桶的数量
for(int j=0;j<b.length;j++) {
bubble[b[j]]++;
}
//把桶的数组顺序求和,那么这时候每个桶中的值就是包括桶下标在内的小于等于它的数量
for(int i=1;i<bubble.length;i++) {
bubble[i]=bubble[i-1]+bubble[i];
}
/*
* 这种方式会多执行很多次,自己手写第一遍就是这样实现的,这样bubble中的值会被当作
* bubble下标值重复的次数,最后也能得到正确的结果
*/
/*for(int k=bubble.length-1;k>=0;k--) {
while(bubble[k]>0) {
c[bubble[k]-1]=k;
bubble[k]--;
}
}*/
//正确实现 从后向前循环,目的是为了保证稳定性
//如原本数组中2 2 2 是在0 1 2的位置 经过上述步骤得到bubble 0 1 3
//第一个2应该是 bubble[2]也就是3 被放在了下标是2的c中,但是原本在的位置是0
for(int i=b.length-1;i>=0;i--) {
int realIndex=--bubble[b[i]];//值在正确排序数组中的位置
c[realIndex]=b[i];
}
return c;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//计数排序:
//1)找出数据中的最大数,确定桶的数量,创建一个maxSize+1的桶数组
//2)把值相等的数据放入到同一个桶中,统计每个桶中的数量(桶下标代表数值,桶中存放值代表重复数据的数量)
//3)把桶的数组顺序求和,那么这时候每个桶中的值就是包括自己在内的小于等于它的个数
//4)从后向前依次循环数组,桶中存储的值就是桶下标值应该在的正确位置(第几个),每次循环减去1得到得就是b[i]应该在c中的位置
int a[]= {3,4,2,1,4,4};
a=CountSort.countSort(a);
for(int i=0;i<a.length;i++) {
System.out.println(a[i]);
}
}
}