1 桶排序
桶排序是计数排序的一个扩展,计数排序相当于每个桶只能存放相同的元素,而桶排序则是可以存放一定区间内的元素,将所有元素放到桶中以后,然后对每个非空桶中的元素进行排序,最后打印输出即可。
1.1 确定桶的个数
确定的个数的方式有很多,比如:
-
可以直接使用和原始数组长度相同的桶的个数,然后每次计算每个元素应该放在哪个桶中
桶的长度:
array.size
max
和min
表示数组中的最大值和最小值
确定每个元素应该放在哪个桶中,使用公式:(max-min)*(array.size-1)/(max-min)
-
可以使用较少的桶,每个桶中存放较多的元素,对每个桶进行排序
桶的长度:
(max-min)/array.size+1
确定每个元素应该放在哪个桶中,使用公式:(max-min)*(array.size)
2 Java代码
import java.util.*;
public class BucketSort {
private double[] array;
private boolean up = true;
public BucketSort(double[] array) {
this.array = array;
}
public BucketSort(double[] array, boolean up) {
this.array = array;
this.up = up;
}
public void increaseSort(){
int n = this.array.length;
double min = this.array[0];
double max = this.array[0];
//找到数组中的最大值和最小值
for (int i = 1; i < n; i++) {
max = Math.max(max,this.array[i]);
min = Math.min(min,this.array[i]);
}
//计算桶的大小
int bucketNum = (int)((max-min)/n+1);
List<List<Double>> bucket = new ArrayList<>(bucketNum); //创建一个桶
for (int i = 0; i < bucketNum; i++) {
bucket.add(new ArrayList<>());
}
for (int i = 0; i < n; i++) {
//计算当前元素需要放在哪个桶中,得到那个桶的下标
int bucIndex = (int)((this.array[i]-min)/n);
bucket.get(bucIndex).add(this.array[i]);
}
//对每个桶中的所有元素进行排序
for (int i = 0; i < bucketNum; i++) {
Collections.sort(bucket.get(i));
}
//将桶中的元素打印输出
int c = 0;
if (up){
for (int i = 0; i < bucketNum; i++) {
for (int j = 0; j < bucket.get(i).size(); j++) {
this.array[c++] = bucket.get(i).get(j);
}
}
}else{
for (int i = bucketNum-1; i >-1; i--) {
for (int j = bucket.get(i).size()-1; j >-1 ; j--) {
this.array[c++] = bucket.get(i).get(j);
}
}
}
}
public void increaseSort1(){
int n = this.array.length;
double min = this.array[0];
double max = this.array[0];
//找到数组中的最大值和最小值
for (int i = 1; i < n; i++) {
max = Math.max(max,this.array[i]);
min = Math.min(min,this.array[i]);
}
//计算桶的大小
List<List<Double>> bucket = new ArrayList<>(n); //创建一个桶
for (int i = 0; i < n; i++) {
bucket.add(new ArrayList<>());
}
for (int i = 0; i < n; i++) {
//计算当前元素需要放在哪个桶中,得到那个桶的下标
int bucIndex = (int)(((this.array[i] - min ) * (n - 1)) / (max-min));
bucket.get(bucIndex).add(this.array[i]);
}
//对每个桶中的所有元素进行排序
for (int i = 0; i < n; i++) {
Collections.sort(bucket.get(i));
}
//将桶中的元素打印输出
int c = 0;
if (up){
for (int i = 0; i < n; i++) {
for (int j = 0; j < bucket.get(i).size(); j++) {
this.array[c++] = bucket.get(i).get(j);
}
}
}else{
for (int i = n-1; i >-1; i--) {
for (int j = bucket.get(i).size()-1; j >-1 ; j--) {
this.array[c++] = bucket.get(i).get(j);
}
}
}
}
public static void main(String[] args) {
double[]a = {12,0.052,4.52,2.01,9.36,1.63};
System.out.println(Arrays.toString(a));
BucketSort bucketSort = new BucketSort(a,false);
bucketSort.increaseSort();
System.out.println(Arrays.toString(a));
bucketSort.increaseSort1();
System.out.println(Arrays.toString(a));
}
}
3 算法复杂度分析
3.1 时间复杂度
由以上代码可以看到,
- 计算数组中的最大值和最小值的,计算量是
n
- 创建桶,并给桶赋初值,计算量是
n
- 将数组中的各个元素分配到桶中,计算量是
n
- 对每个桶中的元素进行排序,当元素分布均匀时,计算量是
n
- 输出桶中的元素,计算量是
n
所以,桶排序的时间复杂度是O(n)
,是一种线性排序,但是仅仅限于数组中元素分布均匀的情况下,如果分布很不均匀,则时间复杂度将退化到O(nlogn)
。
3.2 空间复杂度
由代码可以看出,空间复杂度为O(n)
。