Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 487|回复: 0

[算法学习]详细图解基数排序及java实现

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-11-15 00:00:01 | 显示全部楼层 |阅读模式
    基数排序(radix sort)又称桶排序(bucket sort),相对于常见的比较排序,基数排序是一种分配式排序,即通过将所有数字分配到应在的位置最后再覆盖到原数组完成排序的过程。我在上一篇讲到的计数排序也属于这种排序模式,上一篇结尾处提到了计数排序的稳定性,即排序前和排序后相同的数字相对位置保持不变。今天我们要说的基数排序就要利用到排序稳定性这一点。

    思考过程
       我们回想一下我们小时候是怎么学习比较数字大小的?我们是先比位数,如果一个位数比另一个位数多,那这个数肯定更大。如果位数同样多,就按位数递减依次往下进行比较,哪个数在这一位上更大那就停止比较,得出这个在这个位上数更大的数字整体更大的结论。当然我们也可以从最小的位开始比较,这其实就对应了基数排序里的MSD(most significant digital)和LSD(least significant digital)两种排序方式。     想清楚了这一点之后,我们就要考虑如何存储每一位排序结果的问题了,首先既然作为分配式排序,联想计数排序,每一位排序时存储该次排序结果的数据结构应该至少是一个长度为10的数组(对应十进制该位0-9的数字)。  
      
       
       

         
       

         
       
      
        同时可能存在以下情况:原数组中所有元素在该位上的数字都相同,那一维数组就没法满足我们的需要了,我们需要一个10*n(n为数组长度)的二维数组来存储每次位排序结果。熟悉计数排序结果的读者可能会好奇:为什么不能像计数排序一样,在每个位置只存储出现该数字的次数,而不存储具体的值,这样不就可以用一维数组了?这个我们不妨先思考一下,在对基数排序分析完之后再来看这个问题。  现在我们可以存储每次位排序的结果了,为了在下一位排序前用到这一位排序的结果,我们要将桶里排序的结果还原到原数组中去,然后继续对更改后的原数组执行进一步的位排序操作,如此循环,最后的结果就是数组内元素先按最高位排序,最高位相同的依次按下一位排序,依次递推。得到排序的结果数组。 算法过程


    下面给出一个实例帮助理解: 我们现有一个数组:73, 22, 93, 43, 55, 14, 28, 65, 39, 81 下面是排序过程(二维数组里每一列对应一个桶,因为桶空间没用完,因此没有将二维数组画全): 1.按个位排序

    按第一位排序后数组结果: 81,22,73,93,43,14,55,65,28,39 可以看到数组已经按个位排序了。 2.根据个位排序结果按百位排序

    取出排序结果: 14,22,28,39,43,55,65,73,81,93   可以看到在个位排序的基础上,百位也排序完成(对于百位相同的数子,如22,28,因为个位已经排序,而取出时也保持了排序的稳定性,所以这两个数的位置前后是根据他们个位排序结果决定的)。因为原数组元素最高只有百位,原数组也完成了排序过程。 总结
       我们现在来看看之前遗留的两个问题:为什么不能用一维数组,一定要用二维数组这样的类似桶的结构来存储中间位排序结果?其实之所以要写这个问题,是因为我觉得这个问题是理解基数排序的关键。基数排序本身原理很简单,但是实现中有两个问题需要考虑:1.怎么保留前一位的排序结果,这个问题用之前提到的排序稳定性可以解决。2.怎么关联该位排序结果和原数组元素,二维数组正是为了解决这个问题使用的办法。在计数排序里,虽然保留了所有相等的元素的相对位置,但是这些相等的元素在计数排序里实际是没有差别的,因此我们可以只保存数组里有多少个这样的元素即可。而基数排序里不同,有些元素虽然在某一位上相同,但是他们其他位上很可能不同,如果只保存该位上有多少个5或者多少个6,那关于元素其他位的信息就都丢弃了,这样也就没法对这些元素更高位进行排序了。    弄清基数排序的过程后,我们来看看这个算法的时间复杂度是多少?每次循环遍历数组将元素放在指定位置Θ(n),在从桶中取出数据Θ(n),循环d次(d是位数),时间复杂度就是Θ(r*n)  最后附上基数排序的java实现:
    1. public class RadixSort {
    2. private static void radixSort(int[] array,int d){
    3.   int n=1;//代表位数对应的数:1,10,100...
    4.   int k=0;//保存每一位排序后的结果用于下一位的排序输入
    5.   int length=array.length;
    6.   //排序桶用于保存每次排序后的结果,这一位上排序结果相同的数字放在同一个桶里
    7.   int[][] bucket=new int[10][length];
    8.   int[] order=new int[length];//用于保存每个桶里有多少个数字
    9.   while(n< d)
    10.   {
    11.    for(int num:array) //将数组array里的每个数字放在相应的桶里
    12.    {
    13.      int digit=(num/n)%10;
    14.      bucket[digit][order[digit]]=num;
    15.        order[digit]++;
    16.    }
    17.   
    18.    //将前一个循环生成的桶里的数据覆盖到原数组中用于保存这一位的排序结果
    19.    for(int i=0;i< length;i++)
    20.    {
    21.     if(order[i]!=0)//这个桶里有数据,从上到下遍历这个桶并将数据保存到原数组中
    22.      {
    23.       for(int j=0;j< order[i];j++)
    24.        {
    25.         array[k]=bucket[i][j];
    26.         k++;
    27.        }
    28.      }
    29.      order[i]=0;//将桶里计数器置0,用于下一次位排序
    30.     }
    31.     n*=10;
    32.     k=0;//将k置0,用于下一轮保存位排序结果
    33.   }  
    34. }

    35.   public static void main(String[] args)
    36.   {
    37.     int[] A=new int[]{73,22, 93, 43, 55, 14, 28, 65, 39, 81};
    38.     radixSort(A, 100);
    39.     for(int num:A)
    40.     {
    41.         System.out.println(num);
    42.     }
    43.   }
    44. }
    复制代码
    运行结果:
    C:java>java RadixSort
    14
    22
    28
    39
    43
    55
    65
    73
    81
    93



      
      
       
       

         
       

         
       
      
    复制代码

    源码下载:http://file.javaxxz.com/2014/11/15/000000750.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 07:51 , Processed in 0.356582 second(s), 46 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表