面试官:给我手撕一下基数排序,再考虑一下如何进行改进呢?

简介: 到目前为止我已经把一些常见的排序算法进行了讲解。今天主要关注另外一个排序算法,叫做基数排序。每天学一个知识点,一年之后就会有质的变化。

一、原理


1、计数排序


在正式开始讲解基数排序之前,我们先介绍一个和它同名不同字的排序算法,叫做计数排序。这个计数排序跟基数排序可不一样。可别搞混了。

计数排序的思想是这样的:对每一个输入元素,计算小于它的元素个数,如果有N个元素小于它,那么它就应该放在N+1的位置上。


也就是说,计数排序其实就是根据大小确定一下在整个数组中的位置。如果理解了之后,我们就开始讲一下今天的基数排序。


2、基数排序


相信我们都有查字典的经历,假设我们要查一个字,首先我们根据拼音首字母确定位置,然后根据拼音的第二个字母进一步确定位置,然后根据拼音的第三个字母再进一步确定,就这样一直确定到最后一个字母,直接翻到指定的页码。基数排序就是这样一个思想:


将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。首先从最高位开始排序,接着以此降低,一直到个位。此时整个序列有序。

我们给一张动图来表示一下:链接


上面动图中是这样的排序过程。

(1)第一步:对原始序列按照十位数的大小,分别存放在0到9一共10个桶中。

(2)第二步:对每个桶中的元素,按照个位数进行再排序。


这就是基数排序的整个排序过程。这里还要说一下,我们是从最高位开始往最低位开始进行排的,这叫做MSD。而如果我们从最低位开始往最高位排,叫做LSD。LSD的基数排序适用于位数小的数列,如果位数多的话,使用MSD的效率会比较好。我们知道就OK了。下面我们就使用代码来实现一下。


二、实现


对于代码的实现,我一直以来的思路就是根据其原理,只要原理弄清楚了,代码实现就轻松多了。

//第一点:d表示1、10、100等,序列的最大值长度是2,d就是100。
    private static void radixSort(int[] array, int d) {
        int n = 1;
        int k = 0;
        //从0到9一共10个桶,每个桶最多有array.length个元素。
        int[][] bucket = new int[10][array.length];
        //order表示具体某一个桶
        int[] order = new int[array.length];
        //第二点:只要n小于d,则一直基数排序
        while (n < d) {
            //第三点:将序列的每个数字放在相应的桶里
            for (int num : array) {
                int digit = (num / n) % 10;
                bucket[digit][order[digit]] = num;
                order[digit]++;
            }
            //第四点:将上一次排序的结果覆盖到原数组中
            for (int i = 0; i < array.length; i++){
                //第五点:如果这个桶有数据,依次取出来放到原数组array中。
                if (order[i] != 0){
                    for (int j = 0; j < order[i]; j++) {
                        array[k] = bucket[i][j];
                        k++;
                    }
                }
                order[i] = 0;// 将桶里计数器置0,用于下一次位排序
            }
            n *= 10;
            k = 0;// 将k置0,用于下一轮保存位排序结果
        }
    }

到了这里你会发现一个问题,那就是整个排序过程,没有比较元素之间的大小,只是根据每个数字放在不同的桶里面,放了几遍之后再依次拿出来就是有序的,因此基数排序也叫作“不基于比较”的排序算法。


对于改进,我们该如何考虑呢?


(1)如果我们的数据长度跨度比较大,比如说里面不仅包含了1000,还包含了10000000,这时候如果我们选择以10位基数,那么比较的轮数就会很大,这时候我们可以增大基数。这种方式适合对LSD的改进。


(2)从上面动图中的例子,相信你也会发现,有时候在桶中的元素,明明已经有序了,不过我们还是进入到下一轮进行基数排序了。这时候我们可以增加一个flag,如果在基数为100的时候每个桶内基数排序之后已经有序了,那就没有必要进行下一轮基数为10的排序了,这种适合MSD的改进。


对于基数排序的改进,一直是一个大难题。因为在改进的时候我们需要从两方面考虑,一个是时间复杂度一个是空间复杂度。这里的两个改进思想有一部分也是我参考了网络上其他人的,还问了某某网的HR。


对于时间复杂度的改进,我们主要关注于移动次数和比较次数,在这里基数排序没有比较,但是我们可以尽量减少移动。移动就要保存临时元素,这就要在考虑空间复杂度。当然了还有一点,那就是和其他排序算法结合。来进一步提高。


基数排序的时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数。另外基数排序法是属于稳定性的排序。




相关文章
在使用async/await时,如果异步操作本身没有抛出错误,但是在后续的同步代码中出现了错误,该如何处理?
在使用async/await时,如果异步操作本身没有抛出错误,但是在后续的同步代码中出现了错误,该如何处理?
472 153
|
9月前
|
XML Java Android开发
Android自定义view之网易云推荐歌单界面
本文详细介绍了如何通过自定义View实现网易云音乐推荐歌单界面的效果。首先,作者自定义了一个圆角图片控件`MellowImageView`,用于绘制圆角矩形图片。接着,通过将布局放入`HorizontalScrollView`中,实现了左右滑动功能,并使用`ViewFlipper`添加图片切换动画效果。文章提供了完整的代码示例,包括XML布局、动画文件和Java代码,最终展示了实现效果。此教程适合想了解自定义View和动画效果的开发者。
425 65
Android自定义view之网易云推荐歌单界面
|
数据可视化 项目管理
解读:项目管理中的6大变革模型是什么?怎么用?
本文介绍了6种项目变革管理模型,包括莱温的三步变革模型和科特的八步变革模型。莱温模型适用于重大组织变革和引入新系统或技术,科特模型适用于需要长期适应变革的场合。
413 0
解读:项目管理中的6大变革模型是什么?怎么用?
|
JSON API 开发者
淘宝买家秀数据接口(taobao.item_review_show)丨淘宝 API 实时接口指南
淘宝买家秀数据接口(taobao.item_review_show)可获取买家上传的图片、视频、评论等“买家秀”内容,为潜在买家提供真实参考,帮助商家优化产品和营销策略。使用前需注册开发者账号,构建请求URL并发送GET请求,解析响应数据。调用时需遵守平台规定,保护用户隐私,确保内容真实性。
|
数据管理 测试技术 持续交付
软件测试中的自动化测试策略与最佳实践
在当今快速迭代的软件开发环境中,自动化测试已成为确保软件质量和加速产品上市的关键手段。本文旨在探讨软件测试中的自动化测试策略,包括选择合适的自动化测试工具、构建有效的自动化测试框架以及实施持续集成和持续部署(CI/CD)。通过分析自动化测试的最佳实践,本文为软件开发团队提供了一系列实用的指南,以优化测试流程、提高测试效率并减少人为错误。
400 4
|
网络架构
使用ensp搭建路由拓扑,并使用isis协议实现网络互通实操
使用ensp搭建路由拓扑,并使用isis协议实现网络互通实操
534 0
R语言基于线性回归的资本资产定价模型(CAPM)
R语言基于线性回归的资本资产定价模型(CAPM)
|
SQL 分布式计算 Hadoop
配置Hive使用Spark执行引擎
在Hive中,可以通过配置来指定使用不同的执行引擎。Hive执行引擎包括:默认MR、tez、spark。
1144 0
|
数据可视化 Android开发 iOS开发
FL Studio21中文版水果软件安装教程
FL Studio电脑版本有很多,每个版本各有优点。除了最新版本外,还有历史经典版本,用户可以根据自己的需求进行下载,为了让大家体验到FL Studio更多版本特色,FL Studio专题将会提供FL Studio电脑PC所有版本欢迎查阅下载。 FL Studio21是一款功能十分丰富和强大的音乐编辑软件,能够帮助用户进行编曲、剪辑、录音、混音等操作,让用户能够全面地调整音频,软件对电脑及相应配置的要求不高,使用起来非常方便,提供了一个声音编辑器,声音编辑器可以编辑各种声音,制作理想中的音响效果,对它感兴趣的话就下载安装FL Studio21版吧。
558 0
|
存储 弹性计算 安全
阿里云服务器的实例规格是什么?各个组成部分有什么含义?
有的用户对于阿里云服务器的实例规格是什么并不是很清楚,例如ecs.s6-c1m4.large、ecs.c5.6xlarge,可能大家并不知道实例规格的组成部分分别代表的是什么,有什么含义。下面小编为大家细说一下这些组成部分的含义。
873 0
阿里云服务器的实例规格是什么?各个组成部分有什么含义?

热门文章

最新文章