排序算法-7-基数排序

一、基本思想

基数排序是高效稳定排序,它通过键值的各个位的值,将要排序的元素分配到某些桶中以达到排序的目的,也叫桶子法,是桶排序的扩展。

基数排序图文说明

以这一组数为例: {12,8,29,384,0,912,6}

  • 先按照各位数,将数值放入对应的桶中,遍历完后再从桶中取出存入原数组;

  • 再将数组中的数按照十位上的数,将其放入对应的桶中,遍历完后再从桶中取出存入原数组;
    在这里插入图片描述

  • 最后将数组中的数按照百位上的数,将其放入对应的桶中,遍历完后再从桶中取出存入原数组;在这里插入图片描述
    由于上面这一组数据中,最大的数是三位数,经过3轮排序后,所有数值已经有序排列。

二、代码实现

/**
 *
 * 实现思路:
 * 创建10个桶,下标分别是0~9,每个桶中用于存放数组,将整数按位数切割成不同的数字,再分别按各个位上的数字,将数放到对应下标的桶中。
 * 比如一组数中{12,8,29,384,0,912,6},最大的数是三位数,则:
 *  1)将所有数先按个位上的数大小,将这些数放到对应下标的桶(数组)中;
 *  2)将所有数先按十位上的数大小(不足两位的,十位补零),将这些数放到对应下标的桶(数组)中;
 *  3)将所有数先按百位上的数大小(不足三位的,百位、十位补零),将这些数放到对应下标的桶(数组)中;
 *  最大的数是几位数,就进行几轮分派,直到最后一轮结束,所有数字按已经是有序的了。
 */
public class radixSort {
    public static void main(String[] args) {
//        int[] arr = {12,8,29,384,10,912,6};
        int[] arr = new int[80000000];
        for(int i=0;i<arr.length;i++){
            int random =(int)(Math.random()*10);
            arr[i] = random;
        }
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
        System.out.println("排序前:"+ format.format(new Date() ));
        radixSort(arr);
        System.out.println("排序后:"+format.format(new Date() ));
//        System.out.println(Arrays.toString(arr));
    }

    public static void radixSort(int[] arr){

        //一、创建10个桶(一个10*arr.length 的二维数组)
        //1. 定义一个二维数组,表示10个桶,每个桶是一个一维数组,用于排序时存放数组中的数。
        //2. 为了防止溢出,每个一维数组(桶)的长度为 arr.length 。
        //3. 基数排序是以空间换时间。
        int[][] bucket = new int[10][arr.length];

        //二、从数组中找到最大的数,用来限制循环的轮数
        int maxVal = arr[0];
        for(int i=0;i<arr.length;i++){
            if(arr[i]>maxVal){
                maxVal=arr[i];
            }
        }
        int maxLength = (maxVal+"").length();

        //三、开始对数组中的数进行分派
        //3.1 记录每个桶中存了几个数
        int[] bucketElementCounts = new int[10];

        for(int j = 0,n=1; j<maxLength; j++, n*=10 ){
            for(int k=0; k<arr.length; k++){
                int digitOfElement = arr[k] / n % 10;
                bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[k];
                bucketElementCounts[digitOfElement]++;
            }
            //3.2 一轮结束后,将各个桶中的数取出存到原数组中,取出时根据bucketElementCounts数组可知道每个桶中可以取几个数
            int index = 0;
            for(int p = 0; p<10; p++){
                //如果当前桶中有数则取出
                if(bucketElementCounts[p]!=0){
                    for(int q = 0; q<bucketElementCounts[p]; q++){
                        arr[index++] = bucket[p][q];
                    }
                }
                //从当前桶中获取数完之后,最后将该桶中存储元素的个数设置成0
                bucketElementCounts[p] = 0;
            }
        }
    }
}

三、性能对比

以80000个数据测试,耗时大约12ms
在这里插入图片描述
800000个数据耗时大约220ms
在这里插入图片描述
但是当数据量再大一些的时候,比如80000000个数据,就会报OutOfMemoryError,由于基数排序是采用空间换时间,因此当数据比较大的时候,需要的内存空间会特别大,容易产生空间不足的问题

基数排序所需要的内存空间计算

以80000000个数为例,需要10个桶(数组),每个桶的大小都是80000000,还需要一个长度为10的数组来临时保存每个桶中存了几个数,每个int占4个字节
80000000114/1024/1024/1024约等于 3G,一次计算需要3G的内存空间。
因此在数据量不是很大的时候,基数排序非常快,但是在对海量数据进行排序时,容易造成OutOfMemoryError。

四、 基数排序是稳定的

当对一组数进行排序时,即使这组数中有若干个大小相同的值,但是它们在排序后的相对为止依然保持不变,如:{5,2,7,2,4,2} ,排序后变成 {2,2,2,4,5,7},此时的3个2的相对顺序依然不变,愿数组中的第一个2,在排序后依然排在所有2的第一个位置。这一特性可以被用在将对象多维排序中,比如一组图片按照日期排序后,再按照大小排序,此时,两张同样大小的照片,他们的相对次序依然是按照日期有序排列的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值