目录
桶排序(Bucket Sort)---了解就是可以,平时是不会用的.
计数排序(Counting Sort)
实现案例
初始案例
统计上面的整数出现的次数.
问题的出现:①无法对负整数进行排序 ②极其浪费内存空间 ③是个不稳定的排序
代码步骤:①找出相应的一个最大值与最小值;②开辟空间,存储每个整数出现的次数;③统计每个整数出现的次数;④根据每个整数出现的次数,对整数进行排序.
protected void sort0() {
//1.找出最大数值的那个数
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
} // O(n)
//2.开辟内存空间,存储每个整数出现的次数
int[] counts = new int[1 + max];
//3.统计每个整数出现的次数
for (int i = 0; i < array.length; i++) {
counts[array[i]]++;
} // O(n)
//4.根据整数的出现次数,对整数进行排序
int index = 0;
for (int i = 0; i < counts.length; i++) {
while (counts[i]-- > 0) {
array[index++] = i;
}
} // O(n)
}
上述的计数排序并不是稳定的,因为不知道其出现的次数,这里是可以进行相应的优化的.从效率上看,上面的方式的效率是比较高的,时间复杂度是O(n),比nlog(n)浪费的时间比较多.因此是需要进行改进的.
进阶版
这里进行累加之前的次数的过程是需要进行注意的,对于前面的方式进行了相应的改进. 下述将相应的索引进行了解释.
如果要是倒数第n个7,那么就是相应的次数-n;
public class CountingSort1 extends Sort<Integer> {
@Override
protected void sort() {
// 一:找出最大值
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {//找出来这里的最大值
max = array[i];
}
}
//二:开辟内存空间,存储次数
int[] counts = new int[max + 1];//int数组默认new出来默认都是0
//三:统计每个整数出现的次数,对于每个整数之中的数量进行相应的统计过程使用
for (int i = 0; i < array.length; i++) {
counts[array[i]]++;
}
// 累加次数
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--) {
newArray[ --counts[array[i] ] ] = array[i];
}
// 将有序数组赋值到array
for (int i = 0; i < newArray.length; i++) {
array[i] = newArray[i];
}
}
}
进行复杂度分析:
使用到空间复杂度的两句代码
int[] output = new int[array.length];
int[] counts = new int[max - min +1];
上面两句函数的分析可以得到,最好 最坏 平均时间复杂度:O(n+k);空间复杂度:O(n+k);k是整数的取值范围.___这里就是可以解释前面说过对于一定的整数范围进行排序的过程使用,其属于稳定排序.
最终版 - 对于自定义对象进行相应的排序过程
条件:如果自定义对象可以提供整数类型,仍然是可以使用计数排序进行操作的___这里是以person为例子进行操作.
package com.mj.sort;
public class CountingSort1{
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--) {
//这个地方应当注意放入的是person,不是别的类型了,不要傻乎乎的啦
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 + "]";
}
}
}
基数排序(Radix Sort)
◼ 个位数、十位数、百位数的取值范围都是固定的0~9,可以使用计数排序对它们进行排序.
这里应当注意:如果要是一开始是对于高位排序,之后再对于低位进行排序的话.
package com.mj.sort;
public class RadixSort extends Sort<Integer> {
@Override
protected void sort() {
// 找出最大值,决定相应的排序的次数,由相应的位数进行决定的
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
//这里拿593做例子.
// 个位数: array[i] / 1 % 10 = 3
// 十位数:array[i] / 10 % 10 = 9
// 百位数:array[i] / 100 % 10 = 5
for (int divider = 1; divider <= max; divider *= 10) {
countingSort(divider);
}
}
protected void countingSort(int divider) {
// 开辟内存空间,存储次数
int[] counts = new int[10];
// 统计每个整数出现的次数
for (int i = 0; i < array.length; i++) {
counts[array[i] / divider % 10]++;
}
// 累加次数
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--) {
newArray[--counts[array[i] / divider % 10]] = array[i];
}
// 将有序数组赋值到array
for (int i = 0; i < newArray.length; i++) {
array[i] = newArray[i];
}
}
}
最好 最坏 平均时间复杂度:O(d * (n + k)),d是最大值的位数, k是进制, 属于稳定排序.
空间复杂度:O(n + k),k是进制.
另一种思路
如上图所示,使用二维数组进行操作,过程是比较简单的.
上述的空间复杂度是O(kn + k),时间复杂度是O(dn),d是最大值的位数,k是进制.
桶排序(Bucket Sort)---了解就是可以,平时是不会用的.
执行流程:
这就是一个方法论,很少会考到.
- 空间复杂度:O(n + m),m 是桶的数量
- 时间复杂度
- 因此为 O(n + k),k 为 n ∗ logn − n ∗ logm
-
桶排序属于稳定排序