一、原理
桶排序顾名思义就是得有桶,在桶排序中,我们把未排序数据分成n组,这n组就对应放到n个桶里。那么要把数据放到桶里,有什么规则呢?
首先,我们保证这n个桶是有序的;其次,我们把未排序序列分到这些桶里,然后各个桶分别对数据进行排序;最后,我们按照桶的顺序,把里面的数据按序依次取出,得到一个有序序列,那就是我们最终的排序结果。
举个例子,如图,{21,14,2,3,19,23,6,27,3}是一个无序数组,现在我们要用对它进行桶排序。
首先把桶的范围划分清楚,分别是0-9,10-19,20-29;然后把数组中的数字放入对应范围的桶中;最后在每个桶里面我们都进行各自的排序。现在我们发现每个桶里面的数据都是各自有序的了,可以按照桶的顺序,即0-9,10-19,20-29这样的顺序把数据2,3,3,6,11…全部取出来,赋值回原数组,这就是我们的桶排序结果。
二、实现代码示例
package Sort;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class BucketSort {
public static void main(String[] args) {
int[] arr = {21,14,2,3,19,23,6,11,3};
int[] res = bucketSort(arr);
System.out.println(Arrays.toString(res));
}
public static int[] bucketSort(int[] arr){
// 计算最大值与最小值,方便分桶
int max = Integer.MIN_VALUE; // max设置为最小值,方便比较
int min = Integer.MAX_VALUE; // min设置为最大值,方便比较
// 遍历原数组所有元素,找出数组中的最大值和最小值
for(int i = 0; i < arr.length; i++){
max = Math.max(max, arr[i]);
min = Math.min(min, arr[i]);
}
// 计算桶的数量:元素范围/元素数量 + 1
int bucketNum = (max - min) / arr.length + 1;
ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
for(int i = 0; i < bucketNum; i++){
bucketArr.add(new ArrayList<Integer>());
}
// 根据元素大小将元素分配到对应范围的桶中
for(int i = 0; i < arr.length; i++){
int num = (arr[i] - min) / (arr.length);
bucketArr.get(num).add(arr[i]);
}
// 对每个桶进行排序
for(int i = 0; i < bucketArr.size(); i++){
Collections.sort(bucketArr.get(i));
}
// 将桶中的元素赋值到原序列
int index = 0;
for(int i = 0; i < bucketArr.size(); i++){
for(int j = 0; j < bucketArr.get(i).size(); j++){
arr[index++] = bucketArr.get(i).get(j);
}
}
return arr;
}
}
三、算法分析
1.特点与应用场景
桶排序要求可以很容易地划分到不同桶中,并且所有桶都是有序排列的。
桶排序要求数据跨度范围不是很大,可以均匀分布到每个桶中。若每个桶内部使用快速排序,有的桶中数据非常多,有的桶里数据非常少,那么桶排序的时间复杂度将会退化为O(nlogn)。
桶排序可以说是分治思想的最好体现,它是排序算法中最简单和最快的,但桶排序可能会造成很大的空间消耗。
桶排序比较适合用在外部排序中。所谓的外部排序就是数据存储在外部磁盘中,数据量比较大,内存有限,无法将数据全部加载到内存中。
2.效率分析
设n为元素数量,m为桶的数量,k为每个桶里的元素个数。假设元素均匀划分到m个桶中,则k=n/m。这里我们根据实际情况可知m<=n。
时间复杂度:在排序过程中,我们需要遍历整个元素序列,时间复杂度为O(n);在每个桶中假设使用快速排序,则时间复杂度为O(k* logk),那么m个桶排序的时间复杂度就为O(m* k* logk),当m接近n时,k约等于1,则O(m* k* logk)就是一个很小的常数,此时桶排序的时间复杂度接近O(n)。因此在额外空间充足的情况下,尽量增大桶的数量可以提高桶排序的速度。
空间复杂度:O(n+m)
桶排序的稳定性取决于桶内排序使用的算法。