21、计数排序
1、颜色分类
/**
* 整数 0、1 和 2 分别表示红色、白色和蓝色
* 对它们进行排序, 使得相同颜色的元素相邻, 并按照红色、白色、蓝色顺序排列
*/
@SuppressWarnings("all")
public class SortColors {
/**
* 计数排序
*/
public static void sortColors(int[] nums) {
int[] cnt = new int[3];
for (int num : nums) cnt[num]++;
// 0 [0, cnt0)
// 1 [cnt0, cnt0 + cnt1)
// 2 [cnt0 + cnt1, cnt0 + cnt1 + cnt2)
for (int i = 0; i < cnt[0]; i++) nums[i] = 0;
for (int i = cnt[0]; i < cnt[0] + cnt[1]; i++) nums[i] = 1;
for (int i = cnt[0] + cnt[1]; i < cnt[0] + cnt[1] + cnt[2]; i++) nums[i] = 2;
}
}
2、更一般的计数排序
/**
* 整数 0、1 和 2 分别表示红色、白色和蓝色
* 原地对它们进行排序, 使得相同颜色的元素相邻, 并按照红色、白色、蓝色顺序排列
*/
@SuppressWarnings("all")
public class SortColors {
/**
* 计数排序
*/
public static void sortColors(int[] nums) {
// nums 中的元素固定为 0, 1, 2
// 处理元素取值范围是 [0, R) 的计数排序
int R = 3;
int[] cnt = new int[R];
for (int num : nums) cnt[num]++;
// [index[i], index[i + 1]) 区间的值为 i
int[] index = new int[R + 1];
for (int i = 0; i < R; i++) {
// 右边界 = 左边界 + cnt[i]
index[i + 1] = index[i] + cnt[i];
}
for (int i = 0; i + 1 < index.length; i++) {
// [index[i], index[i + 1]) 区间的值为 i
for (int j = index[i]; j < index[i + 1]; j++) nums[j] = i;
}
}
}
3、计数排序的稳定性
4、实现计数排序
/**
* 计数排序是稳定的 O(N + R)
*/
public class CountingSort {
private CountingSort() {
}
/**
* 计数排序 O(N + R)
*/
public static void sort(Student[] students, int R) {
// 分数的取值范围是 [0, R)
int[] cnt = new int[R];
for (Student student : students) cnt[student.getScore()]++;
// [index[i], index[i + 1]) 区间的值为 i
int[] index = new int[R + 1];
for (int i = 0; i < R; i++) index[i + 1] = index[i] + cnt[i];
Student[] temp = new Student[students.length];
for (Student student : students) {
int score = student.getScore();
temp[index[score]] = student;
index[score] += 1;
}
System.arraycopy(temp, 0, students, 0, temp.length);
}
}
5、验证计数排序的稳定性
public class Student implements Comparable<Student> {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || this.getClass() != o.getClass()) return false;
Student another = (Student) o;
return Objects.equals(name.toLowerCase(), another.name.toLowerCase());
}
@Override
public int compareTo(Student another) {
return this.score - another.score;
}
@Override
public String toString() {
return String.format("Student(name = %s, score = %d)", name, score);
}
}
public class CountingSortTest {
/**
* 验证排序结果是否正确
*/
private static void isSorted(Student[] arr) {
int n = arr.length;
for (int i = 1; i < n; i++) {
if (arr[i - 1].getScore() > arr[i].getScore()) {
throw new RuntimeException("Sort failed!");
}
if (arr[i - 1].getScore() == arr[i].getScore()) {
if (arr[i - 1].getName().compareTo(arr[i].getName()) > 0) {
throw new RuntimeException("Non-Stable counting sort!");
}
}
}
}
/**
* 分数 [0, 101), R = 101
*/
public static void test() {
int n = 26 * 26 * 26 * 26;
Student[] students = new Student[n];
Random random = new Random();
int i = 0;
for (char c1 = 'a'; c1 <= 'z'; c1++)
for (char c2 = 'a'; c2 <= 'z'; c2++)
for (char c3 = 'a'; c3 <= 'z'; c3++)
for (char c4 = 'a'; c4 <= 'z'; c4++)
students[i++] = new Student("" + c1 + c2 + c3 + c4, random.nextInt(101));
CountingSort.sort(students, 101);
isSorted(students);
}
public static void main(String[] args) {
test();
}
}
本文来自博客园,作者:lidongdongdong~,转载请注明原文链接:https://www.cnblogs.com/lidong422339/p/17318453.html