一、原理
计数排序的原理是,统计数组中每个数出现的次数,那么,数组中每个数排序后的位置,就是比它小的数的出现次数累加和。
计数排序于1954年由 Harold H. Seward 提出,它的优势在于在对一定范围内的整数排序时,它的复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法。
当然,这是一种非基于比较的排序算法,它只能适用于数值型的数组。对于非数值型的数组,则不能使用。
而且,它的实现是一种牺牲空间换取时间的做法,当数值范围很大时,也并不适用计数排序。
二、实现过程
1、获取数组中的最大值,创建一个容量为最大值+1的计数数组;
2、遍历原数组,给计数数组对应位置上数值+1,得到每个数出现的次数;
3、对计数数组做累加和,累加和的结果,其实就是排序后的位置索引;
4、遍历原数组,将累加和的结果作为新数组的位置索引,依次将值赋值到新数组,并且,每取出一个值,就在计数数组对应位置-1。
图示:
java实现代码:
// 计数排序
public class CountSort {
public static void main(String[] args) {
Integer[] arr = DataStore.getData();
String source = "";
for(int i = 0; i < arr.length; i++) {
source += arr[i] + " ";
}
System.out.println("原数组:" + source);
int[] sortArr = CountSort.sort(arr);
String res = "";
for(int i = 0; i < sortArr.length; i++) {
res += sortArr[i] + " ";
}
System.out.println("排序后:" + res);
}
// 计数排序
public static int[] sort(Integer[] arr) {
int max = CountSort.getMax(arr);
return CountSort.count(arr, max);
}
// 获取数组中最大值
public static int getMax(Integer[] arr) {
int max = 0;
for(int i = 0; i < arr.length; i++) {
if(arr[i] > max) {
max = arr[i];
}
}
return max;
}
// 计数出现频次,并累加计数得到排序索引
public static int[] count(Integer[] arr, int max) {
// 计数数组,容量大小为原数组的最大值+1,每个位置上的值已被默认初始化为0
int[] countArr = new int[max + 1];
// 辅助数组,存放排序后的数组值
int[] helpArr = new int[arr.length];
// 遍历原数组,给计数数组对应位置数值+1,得到每个数出现的次数
for(int i = 0; i < arr.length; i++) {
countArr[arr[i]] += 1;
}
// 对计数数组做累加和,累加和的结果,其实就是排序后的位置索引
for(int i = 1; i < countArr.length; i++) {
countArr[i] += countArr[i - 1];
}
// 遍历原数组,将累加和的结果作为新数组的位置索引,依次将值赋值到新数组
// 每取出一个值,就在计数数组对应位置-1
for(int i = 0; i < arr.length; i++) {
helpArr[countArr[arr[i]] - 1] = arr[i];
countArr[arr[i]]--;
}
return helpArr;
}
}
DataStore工具类
public class DataStore {
// 随机获取10个整数
public static Integer[] getData() {
List<Integer> list = new ArrayList<Integer>();
for(int i = 0; i < 10; i++) {
double d = Math.random();
list.add((int)(d*10));
}
Integer[] arrays = new Integer[list.size()];
list.toArray(arrays);
return arrays;
}
}
输出:
原数组:4 6 5 4 2 3 2 0 6 9
排序后:0 2 2 3 4 4 5 6 6 9