桶排序又称箱排序(Bucket sort),是一个排序算法,工作的原理是将数组分到有限数量的桶里。每个桶再个别排序(可能在使用其他的排序算法),最后依次把各个桶中的记录列出来便得到了有序序列。桶排序是基数排序的一种归纳结果。当要被排序的数组内的数值平局分配的时候,桶排序使用线性时间( Θ ( n ) \Theta(n) Θ(n))。但桶排序并不是比较排序,它不受 O ( n l o g n ) O(n{\bf log}n) O(nlogn)的时间复杂度影响。
基本思想
桶排序的想法近乎彻底的分治思想。桶排序假设数组均匀分布在一个范围内,并将这一范围划分为几个子范围(桶)。然后利用某种映射函数 f f f,将待排序的关键字 k k k映射到下标为 i i i的同种,那么该关键字 k k k就作为 B [ i ] B[i] B[i]中的元素。接着对每个桶的元素进行排序,并将其依次输出即可得到一个有序的序列。
映射函数一般采用 f = a r r [ i ] / k f=arr[i]/k f=arr[i]/k,其中 k = n k=\sqrt{n} k=n。
如果要是桶排序更加高效可以注意下面两点:
- 在额外空间足够的情况下,增大桶的数量。
- 使用的影射函数尽量能够将输入的 n n n个数据均匀分配到 k k k个桶中。
- 注意桶内元素排序采用的算法,它对性能的影响至关重要。
具体的流程为:
- 设置与一个定量的数组当作空桶。
- 寻访序列,并把元素利用映射函数放入桶中。
- 对每个非空的桶进行排序。
- 从非空的同种将元素一次取出得到排列之后的结果。
代码实现
public class Template {
public void bucketSort(double[] arr) {
int len = arr.length;
ArrayList<LinkedList<Double>> buckets = new ArrayList<>();
for (int i = 0; i < 10; i++) buckets.add(new LinkedList<>());
for (double val : arr) insert(buckets.get(mapping(val)), val);
int ind = 0;
for (LinkedList<Double> bucket : buckets) {
for (Double val : bucket) {
arr[ind++] = val;
}
}
}
/**
* 映射函数
*
* @param val
* @return
*/
public int mapping(double val) {
return (int) val;
}
public void insert(List<Double> bucket, double val) {
ListIterator<Double> it = bucket.listIterator();
boolean flag = true;
while (it.hasNext()) {
if (val <= it.next()) {
it.previous();
it.add(val);
flag = false;
break;
}
}
if (flag) it.add(val);
}
public static void main(String[] args) {
Template temp = new Template();
double[] arr = {0.12, 2.2, 8.8, 7.6, 7.2, 6.3, 9.0, 1.6, 5.6, 2.4};
temp.bucketSort(arr);
System.out.println(Arrays.toString(arr));
}
}
参考文献: