最朴素的实现
已经有详细注释了,懂的都懂,就是用出现的正整数当做数组索引,然后记录元素出现的次数,最后再将记录出现次数的数组遍历出来存储在结果数组中
缺点显而易见,就是只能给正整数排序,而且及其浪费空间。
protected void sort0() { //计数排序 最朴素的实现
// 找出最大值
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
} // O(n)
// 开辟内存空间,存储每个整数出现的次数
int[] counts = new int[1 + max];
// 统计每个整数出现的次数
for (int i = 0; i < array.length; i++) {
counts[array[i]]++;
} // O(n)
// 根据整数的出现次数,对整数进行排序
int index = 0;
for (int i = 0; i < counts.length; i++) {
while (counts[i]-- > 0) {
array[index++] = i;
}
} // O(n)
}
优化后的计数排序
先找出待排序数组的最大值和最小值,然后通过这两个值确定存储出现次数的数组的大小,再遍历原数组,更新counts数组,即更新每个元素出现的次数。记录好之后,再次更新counts数组的每一个值,从1索引位置开始,将每一个元素的值更新为自己和其前面元素值的和。再从后往前遍历原数组,将每一个索引i对应的元素放到newArray数组的- -counts[array[i] - min]索引位置。最后再将有序数组赋值到array
时间复杂度O(n + k),n为数据规模,k为数据范围
protected void sort() {
// 找出最值
int max = array[0];
int min = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) { //最大和最小值可能是相同的,所以两个if
max = array[i];
}
if (array[i] < min) {
min = array[i];
}
}
// 开辟内存空间,存储次数
int[] counts = new int[max - min + 1];
// 统计每个整数出现的次数
for (int i = 0; i < array.length; i++) {
counts[array[i] - min]++; //优化后,array[i] - min就是array[i]这个元素在counts数组的索引
}
// 累加次数
for (int i = 1; i < counts.length; i++) {
counts[i] += counts[i - 1];
}
// 从后往前遍历元素,将它放到有序数组中的合适位置
int[] newArray = new int[array.length];
for (int i = array.length - 1; i >= 0; i--) {
//--counts[array[i] - min],counts[array[i] - min]为当前元素的出现次数,减1即为应存储在新数组中的索引,存储后同时出现次数也减1
newArray[--counts[array[i] - min]] = array[i];
}
// 将有序数组赋值到array
for (int i = 0; i < newArray.length; i++) {
array[i] = newArray[i];
}
}
优化后的计数排序可以排序自定义对象类型,即排序自定义对象数组,自定义对象的int类型的属性作为排序的根据
public static void main(String[] args) {
Person[] persons = new Person[] {
new Person(20, "A"),
new Person(-13, "B"),
new Person(17, "C"),
new Person(12, "D"),
new Person(-13, "E"),
new Person(20, "F")
};
// 找出最值
int max = persons[0].age;
int min = persons[0].age;
for (int i = 1; i < persons.length; i++) {
if (persons[i].age > max) {
max = persons[i].age;
}
if (persons[i].age < min) {
min = persons[i].age;
}
}
// 开辟内存空间,存储次数
int[] counts = new int[max - min + 1];
// 统计每个整数出现的次数
for (int i = 0; i < persons.length; i++) {
counts[persons[i].age - min]++;
}
// 累加次数
for (int i = 1; i < counts.length; i++) {
counts[i] += counts[i - 1];
}
// 从后往前遍历元素,将它放到有序数组中的合适位置
Person[] newArray = new Person[persons.length];
for (int i = persons.length - 1; i >= 0; i--) {
newArray[--counts[persons[i].age - min]] = persons[i];
}
// 将有序数组赋值到array
for (int i = 0; i < newArray.length; i++) {
persons[i] = newArray[i];
}
for (int i = 0; i < persons.length; i++) {
System.out.println(persons[i]);
}
}
private static class Person {
int age;
String name;
Person(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Person [age=" + age
+ ", name=" + name + "]";
}
}