三大线性排序之桶排序

一.概念引入

有作者把计数排序也称为桶排序(各个桶中元素的排序采用计数排序),得到数组C后直接从前往后遍历,输出数组值次数组下标,为0就不输出(或者存入原数组,不稳定),不过笔者认为这种说法不严谨(一个很明显的问题是输出会是双重for循环,不过也有那个意思,叫鸽巢排序也未尝不可),因为桶排序要求输入数据在[0,1)范围内(计数排序要求整数;实际上要么全是整数,要么小数,便于划分桶),先把区间[0,1)划分成n个相同大小的子区间,称为桶,然后将n个输入数分布到各个桶中去。因为输入数均匀且独立分布在[0,1)上,所以,一般不会有很多数落在一个桶中的情况。为了得到结果,先对各个桶中的数进行排序,然后按次序把各桶中的元素列出来。

附上鸽巢排序核心源代码:

   public void pigeonSort(int[] array, int max) {
    int[] c = new int[max];//max是array数组中的最大值
    for(int i=0; i<array.length; i++)
        c[array[i]]++;
    //c数组只是统计元素出现次数
    int k = 0;
    for(int i=0; i<max; i++)
        for(int j=1; j<=c[i]; j++)
            array[k++] = i;
}

二.算法描述

例如要对大小为[1..1000]范围内的n个整数A[1..n]排序,可以把桶设为大小为10的范围,具体而言,设集合B[1]存储[1..10]的整数,集合B[2]存储(10..20]的整数,……集合B[i]存储((i-1)*10, i*10]的整数,i = 1,2,..100。总共有100个桶。然后对A[1..n]从头到尾扫描一遍,把每个A[i]放入对应的桶B[j]中。 然后再对这100个桶中每个桶里的数字排序,这时可用冒泡,选择,乃至快排,一般来说任何排序法都可以。最后依次输出每个桶里面的数字,且每个桶中的数字从小到大输出,这样就得到所有数字排好序的一个序列了。

下图表示出了桶排序作用于有10个数的输入数组上的操作过程。

三.算法的Java实现

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

public class BucketSort {

    public static void bucketSort(double array[]) {
        int length = array.length;
        ArrayList arrList[] = new ArrayList[length];
        /*
         *  每个桶是一个list,存放落在此桶上的元素
         *  上次的基数排序我采用的是计数排序实现的,其实也可以用下面的方法,有兴趣的读者不妨一试(我认为太复杂)
         *  不过效率估计不高(采用了动态数组)
         */
        //划分桶并填元素
        for (int i = 0; i < length; i++) {
            //0.7到0.79放在第8个桶里,编号7;第一个桶放0到0.09
            int temp = (int) Math.floor(10 * array[i]);
            if (null == arrList[temp])
                arrList[temp] = new ArrayList();
            arrList[temp].add(array[i]);
        }
        // 对每个桶中的数进行插入排序
        for (int i = 0; i < length; i++) {
            if (null != arrList[i]) {
                //此处排序方法不定,不过越快越好,除了三大线性排序外,都没有Collections
                //和Arrays里的sort好,因为这是调优后的快拍
                //Arrays里也有,在基数排序里用过copyOf和fill方法
                Collections.sort(arrList[i]);
            }

        }
        //输出类似鸽巢排序
        int count = 0;
        for (int i = 0; i < length; i++) {
            if (null != arrList[i]) {
                Iterator iter = arrList[i].iterator();
                while (iter.hasNext()) {
                    Double d = (Double) iter.next();
                    array[count] = d;
                    count++;
                }
            }
        }
    }

    /*
     * 每个元素满足0<=array[i]<1,貌似还要长度相同,
     * 若是相同小数位(digit),则可以把小数搞为整数,最后再除以10^digit
     *  可以Random.nextInt(101)/100
     */
    public static void main(String[] args) {
        double array[] = { 0.78, 0.17, 0.39, 0.26, 0.72, 0.94, 0.21, 0.12,
                0.23, 0.68 };
        bucketSort(array);
        for (int i = 0; i < array.length; i++)
            System.out.print(array[i] + " ");
        System.out.println();
    }
}

四.算法应用

在面试的海量数据处理题目中,如对每天数以亿计的数据进行排序,直接排序即使采用nlgn的算法,依然是一件很恐怖的事情,内存也无法容纳如此多的数据,这时桶排序就可以有效地降低数据的数量级,再对降低了数量级的数据进行排序,可以得到比较良好的效果。另外也有说桶排序对元组排序,个人认为还是基数排序处理元组比较好,毕竟本身就是多关键字排序,只需要把比较单个数字

原文地址:

http://www.cnblogs.com/hxsyl/p/3214379.html

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-07 10:40:33

三大线性排序之桶排序的相关文章

【算法】计数排序、桶排序和基数排序详解

01.计数排序.桶排序与基数排序 并不是所有的排序 都是基于比较的,计数排序和基数排序就不是.基于比较排序的排序方法,其复杂度无法突破\(n\log{n}\) 的下限,但是 计数排序 桶排序 和基数排序是分布排序,他们是可以突破这个下限达到O(n)的的复杂度的. 1. 计数排序 概念 计数排序是一种稳定的线性时间排序算法.计数排序使用一个额外的数组C,使用 C[i] 来计算 i 出现的次数.然后根据数C来将原数组A中的元素排到正确的位置. 复杂度 计数排序的最坏时间复杂度.最好时间复杂度.平均时

计数排序、桶排序python实现

计数排序在输入n个0到k之间的整数时,时间复杂度最好情况下为O(n+k),最坏情况下为O(n+k),平均情况为O(n+k),空间复杂度为O(n+k),计数排序是稳定的排序. 桶排序在输入N个数据有M个桶时,如果每个桶的数据接近N/M个且桶内使用基于比较的排序,则桶排序的时间复杂度为O(N+M*N/M*log(N/M)).如果N=M时,每个桶只有一个数据,时间复杂度降低为O(N). 桶排序的时间复杂度为O(N+M),桶排序是稳定的排序 1.计数排序 计数排序介绍及C语言实现在:计数排序(链接) d

经典排序算法 - 桶排序Bucket sort

经典排序算法 - 桶排序Bucket sort 补充说明三点 1,桶排序是稳定的 2,桶排序是常见排序里最快的一种,比快排还要快-大多数情况下 3,桶排序非常快,但是同时也非常耗空间,基本上是最耗空间的一种排序算法 我自己的理解哈,可能与网上说的有一些出入,大体都是同样的原理 无序数组有个要求,就是成员隶属于固定(有限的)的区间,如范围为[0-9](考试分数为1-100等) 例如待排数字[6 2 4 1 5 9] 准备10个空桶,最大数个空桶 [6 2 4 1 5 9]           待排

九种经典排序算法详解(冒泡排序,插入排序,选择排序,快速排序,归并排序,堆排序,计数排序,桶排序,基数排序)

综述 最近复习了各种排序算法,记录了一下学习总结和心得,希望对大家能有所帮助.本文介绍了冒泡排序.插入排序.选择排序.快速排序.归并排序.堆排序.计数排序.桶排序.基数排序9种经典的排序算法.针对每种排序算法分析了算法的主要思路,每个算法都附上了伪代码和C++实现. 算法分类 原地排序(in-place):没有使用辅助数据结构来存储中间结果的排序**算法. 非原地排序(not-in-place / out-of-place):使用了辅助数据结构来存储中间结果的排序算法 稳定排序:数列值(key)

冒泡排序,快速排序,归并排序,插入排序,希尔排序,堆排序,计数排序,桶排序,基数排序

选择排序,冒泡排序,快速排序,归并排序,插入排序,希尔排序,计数排序,桶排序,基数排序 以上是一些常用的排序算法. 选择排序 for(int i = 0; i < n; i++) { int minval = a[i]; int minid = i; for (int j = i+1; j < n; j++) { if (a[j] < minval) { minid = j; minval = a[j]; } } swap(a[i], a[minid]); } 最简单的就是选择排序,就是

java-数组排序--计数排序、桶排序、基数排序

计数排序引入 不难发现不论是冒泡排序还是插入排序,其排序方法都是通过对每一个数进行两两比较进行排序的,这种方法称为比较排序,实际上对每个数的两两比较严重影响了其效率,理论上比较排序时间复杂度的最低下限为nlog(n),即任何比较排序的时间复杂度将不会低于nlog(n),那么有没有方法能不经过数列比较就能使数列排序呢 ,她们的时间复杂度又是多少呢??? 计数排序就是一个非比较排序的算法,一如鱼与熊掌不可兼得,她使用了牺牲空间换时间的方法,使的时间复杂度可以达到Ο(n+k) 假设我们有一个数列arr

【排序】基数排序(计数排序、桶排序)

在此对于桶排序做出两种方法: 一.简化版桶排序 代码如下: <span style="font-size:18px;">/*简化版的桶排序*/ #include <stdio.h> int main() { int book[1001],i,j,t,n; for(i=0;i<=1000;i++) { book[i]=0; } scanf("%d",&n);//输入一个数n,表示接下来有n个数 for(i=1;i<=n;i+

排序算法 -- 桶排序

排序算法 -- 目录 桶排序 (Bucket sort)或所谓的箱排序的原理是将数组分到有限数量的桶子里,然后对每个桶子再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序),最后将各个桶中的数据有序的合并起来. 排序过程: 假设待排序的一组数统一的分布在一个范围中,并将这一范围划分成几个子范围,也就是桶 将待排序的一组数,分档规入这些子桶,并将桶中的数据进行排序 将各个桶中的数据有序的合并起来 Data Structure Visualizations 提供了一个桶排序的分

【排序】桶排序

1,桶排序是稳定的 2,桶排序是常见排序里最快的一种,比快排还要快-大多数情况下 3,桶排序非常快,但是同时也非常耗空间,基本上是最耗空间的一种排序算法 思路: 给个数组a,遍历数组a,取出最大的数,申请一个新数组(桶数组),长度为最大的数加1. 将带排序数组中的数,映射到每个桶数组中,桶中记录个数. 遍历同数组,依次取出数字(跳过空桶).