前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >算法渣-排序-桶排序

算法渣-排序-桶排序

作者头像
码农戏码
发布2021-03-23 10:44:42
3330
发布2021-03-23 10:44:42
举报
文章被收录于专栏:DDDDDD

没有一身好内功,招式再多都是空;算法绝对是防身必备,面试时更是不可或缺;跟着算法渣一起从零学算法

线性排序

常见的三种以线性时间运行的算法:计数排序、基数排序和桶排序;网上教程不少,但三者经常混淆,称桶排序但实质可能是计数排序,为了保证原味性,主要参考《算法导论》

需要注意的是线性排序算法是非基于比较的排序算法,都有使用限制才能达到线性排序的效果

定义

桶排序 (Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶子里。

每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。

桶排序是鸽巢排序的一种归纳结果。当要被排序的数组内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))

算法

桶排序的思想:其实就是先分配再收集的这个一个过程

假设输入是一个随机过程产生的[0,1)区间上均匀分布的实数

把区间划分成n个大小相同的子区间,或称为桶。然后将n个输入元素分布的各个桶中去。先对各个桶中的数进行排序,然后按次序把各桶中的数据列出来即可

(因为输入元素均匀而独立的分布在区间 [0,1)上,所以不会出现很多数落在一个桶中的情况)

在桶排序算法中,假设输入的是一个含n个元素的数组A,且每个元素满足0≤A[i]<1。另外,还需要一个辅助数组B[0…n-1]来存放链表(桶),并假设可以用某种机制来维护这些表

刚开始按照示例图的方式理解了桶排序,桶分10个,以十分位为桶号放入各个桶,也算是桶排序一种实现方式,但还是狭隘了


在实际应用时,其实并不然必须元素范围为[0,1),整数,小数都是可以的,只要分布均匀就能最大发挥桶排序优势

优质的桶排序需要考虑几个因素:

  1. 桶的数量:桶越多,占用空间越大
  2. 区间跨度:桶与桶之间的跨度
  3. 桶内元素的排序

一般区间跨度:

除了最后一个桶只包含一个最大值之外,其余各桶之间的区间跨度=(最大值-最小值)/(桶数量-1)

代码语言:javascript
复制
//伪代码
BUCKET_SORT(A)  
n = length(A)   
for i= 1 to n       
    do insert A[i] into list B   
 for i=0 to n-1       
    do sort list B[i] with insertion sort
 concatenate the list B[0]、B[1],,,B[n-1] together in order

实现

代码语言:javascript
复制
private static void bucketSort(double [] array){
    int bucketNum = 10;//10个桶
    double max = Double.MIN_VALUE;
    double min = Double.MIN_VALUE;
    for (double a:array) {
        if(a> max) {
            max = a;
        }
        if(a<min) {
            min = a;
        }
    }
    //区间跨度
    double span  = (max - min) / (bucketNum - 1);
    double [][]buckets = new double[bucketNum][];
    //初始化桶
    for (int b = 0; b<bucketNum;b++) {
        //以排序元素个数初始化每个桶,以防极端情况
        buckets[b] = new double[array.length];
    }
    //每个桶的元素数量
    int [] index = new int[10];
    for (int d = 0;d<array.length;d++) {
        int bucket =  (int)((array[d] - min)/span);
        buckets[bucket][index[bucket]] = array[d];
        index[bucket]++;
    }

    //每个桶排序,直接使用sort函数了
    for(int b = 0; b<10; b++) {
        Arrays.sort(buckets[b]);
    }
    int j = 0;
    for(int b = 0; b<10; b++) {
        if(index[b] == 0) {
            continue;
        }
        //这儿需要特殊处理一下,主要是因为每个桶初始化了array.length,
        // 经过sort排序,比如第一个桶数组变成了[0.0,0.0,......0.002]
        //需要剔掉数组中的0
        for (int bi = array.length-index[b];bi<array.length;bi++) {
            array[j++] = buckets[b][bi];
        }
    }
}

复杂度

时间复杂度:

假设有m个桶,则每个桶的元素为n/m;

当辅助函数为冒泡排序O(n^2)时,桶排序为 O(n)+mO((n/m)2);

当辅助函数为快速排序时O(nlgn)时,桶排序为 O(n)+m*O(n/m log(n/m))

空间复杂度:

O(M+N)

通常桶越多,执行效率越快,即省时间,但是桶越多,空间消耗就越大,是一种通过空间换时间的方式

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-01-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农戏码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 线性排序
  • 定义
  • 算法
  • 实现
  • 复杂度
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档