计数排序(Counting Sort)是一种非比较型整数排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
计数排序的使用条件和范围
-
使用条件:
- 输入的数据必须是整数。
- 输入数据的范围已知(即存在最大值和最小值)。
-
使用范围:
- 适用于一定范围内的整数排序。
- 当输入的数据范围k不是很大时,计数排序非常高效。
- 如果k远大于n(n是数据个数),则计数排序不是最佳选择,因为会浪费很多空间。
/* * 计数排序 * */ public static int[] sortNumber(int[] array){ int max = Integer.MIN_VALUE; for (int num : array){ max = Math.max(max, num); } int[] store = new int[max + 1]; for (int i = 0; i < array.length; i++) { store[array[i]]++; } //写法1 int index = 0; for (int i = 0; i < store.length; i++) { for (int j = 0; j < store[i]; j++) { array[index] = i; index++; } } //写法2 int sortedIndex = 0; for (int j = 0; j < bucketLen; j++) { while (store[j] > 0) { arr[sortedIndex++] = j; store[j]--; } } return array; } }
计数排序的Java示例
以下是一个Java示例,展示了如何使用计数排序对一个整数数组进行排序。假设我们要排序的整数都在0到100之间(即k=101):
public class CountingSort {
public static void countingSort(int[] arr) {
if (arr == null || arr.length == 0) return;
// 找出数组中的最大值和最小值
int max = arr[0], min = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) max = arr[i];
if (arr[i] < min) min = arr[i];
}
// 计数数组的长度设为最大值+1
int range = max - min + 1;
int[] count = new int[range];
// 填充计数数组
for (int i = 0; i < arr.length; i++) {
count[arr[i] - min]++;
}
// 累加计数数组,使其变为前缀和
for (int i = 1; i < count.length; i++) {
count[i] += count[i - 1];
}
// 从后向前遍历原数组,根据计数数组填充结果数组
int[] sortedArr = new int[arr.length];
for (int i = arr.length - 1; i >= 0; i--) {
sortedArr[count[arr[i] - min] - 1] = arr[i];
count[arr[i] - min]--;
}
// 将结果数组复制到原数组
System.arraycopy(sortedArr, 0, arr, 0, arr.length);
}
public static void main(String[] args) {
int[] arr = {4, 2, 2, 8, 3, 3, 1};
countingSort(arr);
for (int num : arr) {
System.out.print(num + " ");
}
}
}
注意:
- 在这个例子中,我们首先找到了数组中的最大值和最小值,以确定计数数组的大小。
- 计数数组
count
的索引对应于原数组中的元素值减去最小值min
,这是因为我们假设所有元素都是非负整数,并希望从0开始计数。 - 累加计数数组使其成为前缀和,这样我们可以知道每个元素在排序后数组中的位置。
- 从后向前遍历原数组,并使用计数数组来确定每个元素在排序后数组中的位置。这样做是为了稳定排序(即相等元素的相对顺序不变)。
- 最后,我们将排序后的数组复制回原数组。