排序算法之桶排序
简介
桶排序(Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶子里,每个桶子再个别排序,有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序。
桶排序是鸽巢排序的一种归纳结果。当要被排序的数组内的数值是均匀分配的时候,桶排序使用线性时间 \(Θ(n)\)。但桶排序并不是 比较排序,他不受到 \(O(n log n)\) 下限的影响。
基本思想
桶排序的基本思想是:把数组 num 划分为n个大小相同子区间(桶),每个子区间各自排序,最后合并。
计数排序是桶排序的一种特殊情况,可以把计数排序当成每个桶里只有一个元素的情况。
排序过程:
(1)找出待排序数组中的最大值 max、最小值 min;
(2)我们使用 动态数组 ArrayList 作为桶,桶里放的元素也用 ArrayList 存储;
桶的数量为 \((max - min) / num.length + 1\);
(3)遍历数组 num,计算每个元素 num[i] 应该放在哪个桶;
(4)每个桶各自排序;
(5)遍历桶数组,把排序好的元素放回原数组。
排序过程
(图片参考:https://blog.csdn.net/qq_37186247/article/details/100834916)
代码实现
import java.util.*;
/**
* 桶排序
* @Author distance
*/
public class BucketSort {
public static void sort(int[] num) {
// 找最大值和最小值
int max = Integer.MIN_VALUE , min = Integer.MAX_VALUE;
for (int i = 0; i < num.length; i++) {
if (num[i] > max) {
max = num[i];
}
if (num[i] < min) {
min = num[i];
}
}
// 桶数
int bucketNum = (max - min) / num.length + 1;
List<ArrayList<Integer>> bucketArray = new ArrayList<>(bucketNum);
for (int i = 0; i < bucketNum; i++) {
bucketArray.add(new ArrayList<Integer>());
}
// 将每个元素放入桶,通过值计算这个元素分在哪个桶
int index;
for (int i = 0; i < num.length; i++) {
index = (num[i] - min) / num.length;
bucketArray.get(index).add(num[i]);
}
// 对每个桶排序
for (int i = 0; i < bucketArray.size(); i++) {
Collections.sort(bucketArray.get(i));
}
// System.out.println(bucketArray.toString());
// 加入原数组
index = 0;
for (ArrayList<Integer> integers : bucketArray) {
for (int j = 0; j < integers.size(); j++) {
num[index++] = integers.get(j);
}
}
}
public static void main(String[] args) {
int[] num = {4,1,7,9,2,5,2,3,2};
BucketSort.sort(num);
for (int i = 0; i < num.length; i++) {
System.out.print(num[i] + " ");
}
}
}
算法分析
时间复杂度
对于 \(n\) 个待排数据,\(m\) 个桶,平均每个桶 \(n/m\) 个数据的桶排序,平均时间复杂度为:
\(O(n) + O(m * (n/m) * log_2(n/m)) = O(n + n * (log_2n-log_2m)) = O(n + n * log_2n - n * log_2m)\)
当 \(n = m\) 时,即极限情况下每个桶只有一个数据时。桶排序的最好效率能够达到 \(O(n)\)。
如果相对于同样的 \(n\),桶数量 \(m\) 越大,其效率越高,最好的时间复杂度达到 \(O(n)\)。
所以桶排序的平均时间复杂度为 O(n+c),其中 c = n * (logn-logm)。
算法稳定性
如果桶排序中,对各个桶的排序算法是基于不稳定的排序算法,例如快排实现,那么桶排序就不是稳定的排序算法;
反之,如果桶排序是基于稳定的排序算法,例如归并排序实现,那么桶排序可以完成稳定的排序。
所以,桶排序的稳定性取决于桶内排序使用的算法。