基数排序详解(LSD方法+MSD方法+思路+图解+代码)


基数排序


一、基数排序

概念

  • 基数排序是一种非比较型整数排序算法

  • 将整数按位数切割成不同的数字,然后按每个位数分别比较

  • 使用场景:按位分割进行排序,适用于大数据范围排序,打破了计数排序的限制

  • 稳定性:稳定

  • 按位分割技巧:arr[i] / digit % 10,其中digit为10^n。

在这里插入图片描述

1.LSD排序法(最低位优先法)

  • 从最低位向最高位依次按位进行计数排序。

  • 进出的次数和最大值的位数有关

  • 桶可以用队列来表示

  • 数组的每个元素都是队列

在这里插入图片描述

  • 1.先遍历找到最大值
  • 2.求出最高位

在这里插入图片描述

    public static void radixSortR(int[] array) {
        //10进制数,有10个桶,每个桶最多存array.length个数
        int[][] bucket = new int[10][array.length];
        //桶里面要存的具体数值

        int[] bucketElementCounts = new int[10];
        //用来计算,统计每个桶所存的元素的个数,每个桶对应一个元素

        //1.求出最大数
        int MAX = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] > MAX) {
                MAX = array[i];
            }
        }
        //求最大值的位数,先变成字符串,求字符串长度
        int MAXCount = (MAX + "").length();
        //最大位数的个数,进行几次计数排序
        for (int i = 0; i < MAXCount; i++) {//i代表第几次排序
            //放进桶中
            for (int k = 0; k < array.length; k++) {
                //k相当于遍历待排数值
                //array[k] /(int) Math.pow(10, i)%10 求出每次要比较位的数
                //求的是个位,并且是对应趟数的个位
                int value = (array[k] / (int) Math.pow(10, i)) % 10;
                //根据求出的位数,找到对应桶,放到对应桶的位置
                bucket[value][bucketElementCounts[value]] = array[k];
                //不管value 为多少,bucketElementCounts[value]的值都为0
                //相当于存到对应桶的0位bucket[value][0]
                bucketElementCounts[value]++; //从0->1
                //对应桶的技术数组开始计数
            }

            //取出每个桶中的元素,赋值给数组
            int index = 0;//array新的下标
            for (int k = 0; k < bucketElementCounts.length; k++) {//遍历每个桶
                if (bucketElementCounts[k] != 0) {//桶里有元素
                    for (int j = 0; j < bucketElementCounts[k]; j++) {//比那里每个桶的元素
                        array[index] = bucket[k][j];
                        index++;
                    }
                }
                bucketElementCounts[k] =0;//每个桶遍历完后,清空每个桶的元素;
            }
        }
    }

2.MSD排序法(最高位优先法)

在这里插入图片描述

  • 从最高位向最低位依次按位进行排序。
  • 按位递归分组收集
  • 1.查询最大值,获取最高位的基数
  • 2.按位分组,存入桶中
  • 3.组内元素数量>1,下一位递归分组
  • 4.组内元素数量=1.收集元素
   /**
     * 基数排序--MSD--递归
     * @param array
     */

    public static void radixSortMSD(int[] array) {
        //1.求出最大数
        int MAX = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] > MAX) {
                MAX = array[i];
            }
        }
        //求最大值的位数,先变成字符串,求字符串长度
        int MAXCount = (MAX + "").length();
        // 计算最大值的基数
        int radix = new Double(Math.pow(10, MAXCount - 1)).intValue();

        int[] arr = msdSort(array, radix);
        System.out.println(Arrays.toString(arr));
    }
    public static int[] msdSort(int[] arr, int radix){
        // 递归分组到个位,退出
        if (radix <= 0) {
            return arr;
        }
        // 分组计数器
        int[] groupCounter = new int[10];

        // 分组桶
        int[][] groupBucket = new int[10][arr.length];

        for (int i = 0; i < arr.length; i++) {
            // 找分组桶位置
            int position = arr[i] / radix % 10;
            // 将元素存入分组
            groupBucket[position][groupCounter[position]] = arr[i];
            // 当前分组计数加1
            groupCounter[position]++;
        }

        int index = 0;
        int[] sortArr = new int[arr.length];


        // 遍历分组计数器
        for (int i = 0; i < groupCounter.length; i++) {
            // 组内元素数量>1,递归分组
            if (groupCounter[i] > 1) {
                int[] copyArr = Arrays.copyOf(groupBucket[i], groupCounter[i]);
                // 递归分组
                int[] tmp = msdSort(copyArr, radix / 10);
                // 收集递归分组后的元素
                for (int j = 0; j < tmp.length; j++) {
                    sortArr[index++] = tmp[j];
                }
            } else if (groupCounter[i] == 1) {
                // 收集组内元素数量=1的元素
                sortArr[index++] = groupBucket[i][0];
            }
        }
        return sortArr;
    }

点击移步博客主页,欢迎光临~

偷cyk的图

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值