ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

基数排序原理及Java实现

2020-12-31 11:34:23  阅读:192  来源: 互联网

标签:10 arr Java int Digit 存进 基数排序 原理 排序


基数排序算法思路图解

基数排序(桶排序)介绍:

基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是通过键值的各个位的值,将要排序的元素分配至某些“桶”中,达到排序的作用

基数排序法是属于稳定性的排序,基数排序法的是效率高的稳定性排序法

基数排序(Radix Sort)是桶排序的扩展

基数排序是1887年赫尔曼·何乐礼发明的。它是这样实现的:将整数按位数切割成不同的数字,然后按每个位数分别比较。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
基数排序轮数取决于原数组中最大数的位数

基数排序代码实现

用二维数组表示10个桶,为了防止放入数据时溢出,每个一位数组的大小都定义为arr.length,基数排序是用空间换时间

取每个桶中的数据时不确定每个桶中有几个元素?
每放入一次数据就要记录每一个桶中有几个有效数据(定义一个一位数组来记录放入数据的个数)
int[] bucketElementCounts
第一轮 排序,按个位数存进桶

public static void baseSort(int arr[])
    {
       //创建一个二维数组,每一维存放个位相同的数 比如第0维就存放个位为0的数
        int[][]Digit=new int[10][arr.length];
        //定义一个一维数组,计数每一维是否存有数据
        int[]DimCount=new int[10];
        //第一轮排序,按个位存进十个桶
        System.out.println("第一轮排序,按个位存进十个桶");
        for(int i=0;i<arr.length;i++)
        {
            Digit[arr[i]%10][DimCount[arr[i]%10]]=arr[i];//找出待排序数的个位数,然后存进和这个个位数相应的桶,个位是1,就存进编号为1的桶(即Digit[0][]),个位是10,就存进编号为0的桶(即Digit[1][])
            DimCount[arr[i]%10]++;//哪个桶存进了数,这个桶中的数的数量就加1,方便后续再存入数,DimCount[arr[i]%10]是二维数组Digit的第二个下标
        }
        for(int i=0;i<10;i++)
        {
            for(int j=0;j<arr.length;j++)
            {
                System.out.print(Digit[i][j]+" ");
            }
            System.out.println();//打印一行就换行
        }
    }

测试 int[]arr={123,36,78,58,94,63,72,45};

第一轮排序,按个位存进十个桶
0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 
72 0 0 0 0 0 0 0 
123 63 0 0 0 0 0 0 
94 0 0 0 0 0 0 0 
45 0 0 0 0 0 0 0 
36 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 
78 58 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 

第二轮 排序,按十位数存进桶
每一轮排完记得清桶里面的数据,把负责基数的数组清空即可,这样我们下一次王桶里放数据就是从每个桶的下标0开始存,在把这个下标对应的桶中的元素数量加1,我们排完从桶种取出数据的时候,只取到每一个桶对应的计数就好了。


   //把第一轮拍好序的数从桶里拿出来放进数组,第二轮再对这个数组进行排序
        int count=0;
         for(int i=0;i<10;i++)
         {
             for(int j=0;j<DimCount[i];j++)
             {
                 arr[count++]=Digit[i][j];
             }
             DimCount[i]=0;//把计数清零,以便下一轮排序再往二维数组放数据
         }

 //第二轮排序,按十位存进十个桶
        System.out.println("第二轮排序,按十位存进十个桶");

        for(int i=0;i<arr.length;i++)
        {
            Digit[arr[i]/10%10][DimCount[arr[i]/10%10]]=arr[i];//找出待排序数的十位数,然后存进和这个十位数相应的桶,十位是1,就存进编号为1的桶(即Digit[1][])
            DimCount[arr[i]/10%10]++;
        }

第三轮 排序,按百位数存进桶
每一轮排完记得清桶里面的数据

        //第三轮排序,按百位存进十个桶
        System.out.println("第三轮排序,按百位存进十个桶");

        for(int i=0;i<arr.length;i++)
        {
            Digit[arr[i]/100%10][DimCount[arr[i]/100%10]]=arr[i];//找出待排序数的十位数,然后存进和这个十位数相应的桶,十位是1,就存进编号为1的桶(即Digit[1][])
            DimCount[arr[i]/100%10]++;
        }

        count=0;
        for(int i=0;i<10;i++)
        {
            for(int j=0;j<DimCount[i];j++)
            {
                arr[count++]=Digit[i][j];
            }
            DimCount[i]=0;//把计数清零,以便下一轮排序再往二维数组放数据
        }
        System.out.println(Arrays.toString(arr));

在这里插入图片描述
接下来我们把代码合并

public static void BaseSort2(int arr[]) {

        //创建一个二维数组,每一维存放个位相同的数 比如第0维就存放个位为0的数
        int[][] Digit = new int[10][arr.length];
        //定义一个一维数组,计数每一维是否存有数据
        int[] DimCount = new int[10];

        //先获取外循环的轮数,最多3位数就循环3轮,所以需要先找到最大的数是几位的
        int  max=0;
        for(int i=0;i<arr.length;i++)
        {
            if(arr[i]>max)
            {
                max=arr[i];
            }
        }
        int maxLength=(max+"").length();//骚操作,转成字符串看长度

        for (int k = 0,n=1; k < maxLength; k++,n*=10) {//注意n*=10,自己理解一下吧,结合分部循环
            for (int i = 0; i < arr.length; i++ ) {
                Digit[arr[i] / n % 10][DimCount[arr[i] / n % 10]] = arr[i];//找出待排序数的个位数,然后存进和这个个位数相应的桶,个位是1,就存进编号为1的桶(即Digit[1][]),个位是0,就存进编号为0的桶(即Digit[0][])
                DimCount[arr[i] / n % 10]++;//哪个桶存进了数,这个桶中的数的数量就加1,方便后续再存入数,DimCount[arr[i]%10]是二维数组Digit的第二个下标
            }
            //把上一轮排好序的数从桶里拿出来放进数组,下一轮再对这个数组进行排序
            for (int i = 0, count = 0; i < 10; i++) {
                for (int j = 0; j < DimCount[i]; j++) {
                    arr[count++] = Digit[i][j];
                }
                DimCount[i] = 0;//把计数清零,以便下一轮排序再往二维数组放数据
            }
            System.out.println(Arrays.toString(arr));
        }
    }

在这里插入图片描述
我们再来测试80个数据
在这里插入图片描述好测试无误,我们测试一下80000个数需要排序多久
在这里插入图片描述
800000
在这里插入图片描述
8000000
在这里插入图片描述
80000000
在这里插入图片描述

基数排序算法注意事项

当数据量较小,速度比快排和归并还快,但是当数据量比如达到8000万,因为排序之前会开10个桶,每个桶的长度都跟数据量一样大,那么占用内存(空间)就会很大

80000000×11×4/1024/1024/1024=3.3G,占用内存3.3个G(相当于11个数组,一个int是4个字节,1k=1024字节,1M=1024k,1G=1024M)
在这里插入图片描述基数排序的稳定性说明
3 1 4 1 5 7 2
排序之后
1 1 2 3 4 5 7
可以看到数组里面有2个 1,排序前后,两个1的顺序是不变的,原来哪一个1在前面,排序之后它依然在前面

基数排序的说明:
基数排序是对传统桶排序的扩展,速度很快.
基数排序是经典的空间换时间的方式,占用内存很大,(因为我们开了一个二维数组) 当对海量数据排序时,容易造成 OutOfMemoryError 。
基数排序是稳定的。[注:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的]
有负数的数组,我们不用基数排序来进行排序, 如果要支持负数,参考: https://code.i-harness.com/zh-CN/q/e98fa9

负数排序方案:取余的绝对值放入桶中,再取出来数据时要进行反转

标签:10,arr,Java,int,Digit,存进,基数排序,原理,排序
来源: https://blog.csdn.net/ningmengshuxiawo/article/details/112005178

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有