桶排序
算法原理
介绍
桶排序(Bucket sort)或 箱排序,原理是将数组分到有限数量的桶里, 然后对每个桶分别排序(可能使用别的排序算法或已递归方式继续使用桶排序进行排序),最后将各个桶的数据有序地合并起来。
假设一组数据,arr = [2, 1, 7, 0, 3, 4, 5, 9, 6, 8];
使用冒泡排序, 所需时间为:
102=100
使用桶排序,将10条数据分到两个桶子里: bucket1 = [2,1,0,3,4], bucket2 = [7,5,9,6,8]
分别使用冒泡排序,所需时间为
52+52=50
排序过程
- 设置一个定量的数组当做空桶子
- 遍历数组,把每个元素放到对应的桶子里去
- 对每个不是的空桶子进行排序
- 从不是空的桶子里把元素再放回原来的数组中
查看分步动画演示
性能
N个待排数据, M个桶
平均每个桶[N/M]个数据的桶排序平均时间复杂度为:
O(N)+O(M*(N/M)*log(N/M))=O(N+N*(logN-logM))=O(N+N*logN-N*logM)
设: K=N*(logN-logM)
- 平均时间复杂度 O(N + k)
- 空间复杂度 O(N + M)
- 最差时间复杂度 O(N ^ 2)
当N=M时, 极限情况下每个桶只有一个数据时,桶排序的最好效率能达到O(N)
应用
- 对500W个考生的分数进行排名
- 分析: 如果使用快排,平均比较次数为O(5E6 * log5E6)≈1.112E8.但是
我们发现这些数据有特殊的条件:100<=score<=900.那么我们就可以考虑使用桶排序 - 方法:创建801(100 ~ 900)个桶,将每个考生的分数丢进f(score) = score - 100的桶中,
从头到尾遍历一遍数据仅需500W次,然后根据桶号大小依次将桶中数值输出,
就可以得到一个有序的序列,而且可以很容易的到每个分数对应的考生数。
- 分析: 如果使用快排,平均比较次数为O(5E6 * log5E6)≈1.112E8.但是
- 在一个文件中有10G整数,乱序排列,要求找出中位数。内存限制为 2G。
- 分析
- 思想
- 方法
局限
- 不适合元素值集合很大的情况
程序实现
Javascript 实现
class Node{
constructor(value, next){
this.value = value;
this.next = next;
}
toString(){
var array = [];
var node = this;
while(node){
array.push(node.value);
node = node.next;
}
return array.join("->");
}
}
function insert(head, value){
if(!head){
return new Node(value);
}
if(value < head.value){
return new Node(value, head);
}
var node = head;
while(node){
var next = node.next;
if(!next){
node.next = new Node(value);
break;
}else if(next.value > value){
node.next = new Node(value, node.next);
break;
}else{
node = next;
}
}
return head;
}
function merge(bucket, array, order){
if(!order){
order = "asc";
}
var elementIndex;
var step;
if(order === "desc"){
elementIndex = array.length - 1;
step = -1;
}else{
elementIndex = 0;
step = 1;
}
bucket.forEach(node => {
while(node){
array[elementIndex] = node.value;
elementIndex += step;
node = node.next;
}
});
}
function bucketSort(array, order){
if(!array || array.length < 2){
return array;
}
var bucket = [],
numberOfElements = array.length,
maximumArrayValue = Math.max.apply(Math, array)
minimumArrayValue = Math.min.apply(Math, array),
ratio = numberOfElements / (maximumArrayValue - minimumArrayValue + 1);
bucket.length = numberOfElements;
array.forEach(value => {
var index = Math.floor((value - minimumArrayValue) * ratio);
var head = bucket[index];
// 按大小顺序插入到桶中
bucket[index] = insert(head, value);
});
// 合并结果
merge(bucket, array, order);
return array;
}
Java 实现
public void bucketSort(int[] array){
}
Python 实现
def bucketSort():
pass;