- 概念:计数排序是一种不基于比较的排序算法,主要思想是先计算出待排序序列的最大值 maxValue 与 最小值 minValue,再开辟一个长度为 maxValue - minValue + 1 的额外空间,然后统计待排序序列中每个元素的数量,记录在额外空间中,最后遍历一遍额外空间,按照顺序把每个元素赋值到原始序列中。
- 图解
- 代码
import java.util.Arrays;
public class CountSort {
// 计数排序,a 是数组,n 是数组大小。假设数组中存储的都是非负整数。
public static void countingSort(int[] a, int n) {
if (n <= 1) return;
// 查找数组中数据的范围
int max = a[0];
for (int i = 1; i < n; ++i) {
if (max < a[i]) {
max = a[i];
}
}
int[] c = new int[max + 1]; // 申请一个计数数组 c,下标大小 [0,max]
for (int i = 0; i <= max; ++i) {
c[i] = 0;
}
// 计算每个元素的个数,放入 c 中
for (int i = 0; i < n; ++i) {
c[a[i]]++;
}
// 依次累加
for (int i = 1; i <= max; ++i) {
c[i] = c[i-1] + c[i];
}
// 临时数组 r,存储排序之后的结果
int[] r = new int[n];
// 计算排序的关键步骤,有点难理解
for (int i = n - 1; i >= 0; --i) {
int index = c[a[i]]-1;
r[index] = a[i];
c[a[i]]--;
}
// 将结果拷贝给 a 数组
for (int i = 0; i < n; ++i) {
a[i] = r[i];
}
}
public static void main(String[] args) {
int[] array = new int[]{3, 4, 2, 1, 5, 6, 7, 8};
countingSort(array, array.length);
System.out.println(Arrays.toString(array));
}
}
复杂度分析和是否稳定
-
1. 时间复杂度:O(n+k)
当待排序元素是 n 个 0 到 k 之间的整数时,时间复杂度是 O(n+k) O(n+k)O(n+k)。2. 额外空间复杂度:O(n+k)
计数排序需要两个额外的数组,分别用于记录元素数量与排序结果。 -
生成排序结果的过程(28行),是从后向前遍历的,也就是说原始数组中先出现的元素依旧会在前面。
所以,计数排序是稳定的排序算法。