看动画学算法之:排序-基数排序

简介: 看动画学算法之:排序-基数排序

目录



简介


之前的文章我们讲了count排序,但是count排序有个限制,因为count数组是有限的,如果数组中的元素范围过大,使用count排序是不现实的,其时间复杂度会膨胀。


而解决大范围的元素排序的办法就是基数排序。


基数排序的例子


什么是基数排序呢?


考虑一下,虽然我们不能直接将所有范围内的数字都使用count数组进行排序,但是我们可以考虑按数字的位数来进行n轮count排序,每一轮都只对数字的某一位进行排序。


最终仍然可以得到结果,并且还可以摆脱count数组大小的限制,这就是基数排序。


假如我们现在数组的元素是:1221, 15, 20, 3681, 277, 5420, 71, 1522, 4793。


先看动画,看下最直观的基数排序的过程:



在上面的例子中,我们先对个位进行count排序,然后对十位进行count排序,然后是百位和千位。


最后生成最终的排序结果。


基数排序的java代码实现


因为基数排序实际上是分别按位数的count排序。所以我们可以重用之前写的count排序的代码,只是需要进行一些改造。


doCountingSort方法除了传入数组外,还需要传入排序的位数digit,我们用1,10,100,1000来表示。


看一下改造过后的doCountingSort方法:


public void doRadixSort(int[] array, int digit){
        int n = array.length;
        // 存储排序过后的数组
        int output[] = new int[n];
        // count数组,用来存储统计各个元素出现的次数
        int count[] = new int[10];
        Arrays.fill(count,0);
        log.info("初始化count值:{}",count);
        // 将原始数组中数据出现次数存入count数组
        for (int i=0; i<n; ++i) {
            count[(array[i]/digit)%10]++;
        }
        log.info("count之后count值:{}",count);
        // 这里是一个小技巧,我们根据count中元素出现的次数计算对应元素第一次应该出现在output中的下标。
        //这里的下标是从右往左数的
        for (int i=1; i<10; i++) {
            count[i] += count[i - 1];
        }
        log.info("整理count对应的output下标:{}",count);
        // 根据count中的下标,构建排序后的数组
        //插入一个之后,相应的count下标要减一
        for (int i = n-1; i>=0; i--)
        {
            output[count[(array[i]/digit)%10]-1] = array[i];
            count[(array[i]/digit)%10]--;
        }
        log.info("构建output之后的output值:{}",output);
        //将排序后的数组写回原数组
        for (int i = 0; i<n; ++i)
            array[i] = output[i];
    }


跟count排序变化不大,区别就是这里我们需要使用count[(array[i]/digit)%10],来对每一位进行排序。


另外,为了计算出位数digit的值,我们还需要拿到数组中最大元素的值:


public int getMax(int[] array)
    {
        int mx = array[0];
        for (int i = 1; i < array.length; i++)
            if (array[i] > mx){
                mx = array[i];
            }
        return mx;
    }


看下怎么调用:


public static void main(String[] args) {
        int[] array= {1221, 15, 20, 3681, 277, 5420, 71, 1522, 4793};
        RadixSort radixSort=new RadixSort();
        log.info("radixSort之前的数组为:{}",array);
        //拿到数组的最大值,用于计算digit
        int max = radixSort.getMax(array);
        //根据位数,遍历进行count排序
        for (int digit = 1; max/digit > 0; digit *= 10){
            radixSort.doRadixSort(array,digit);
        }
    }


看下输出结果:


image.png


很好,结果都排序了。


基数排序的时间复杂度


从计算过程我们可以看出,基数排序的时间复杂度是O(d*(n+b)) ,其中b是数字的进制数,比如上面我们使用的是10进制,那么b=10。


d是需要循环的轮数,也就是数组中最大数的位数。假如数组中最大的数字用K表示,那么d=logb(k)。


综上,基数排序的时间复杂度是O((n+b) * logb(k))。


当k <= nc,其中c是常量时,上面的时间复杂度可以近似等于O(nLogb(n))。


考虑下当b=n的情况下,基数排序的时间复杂度可以近似等于线性时间复杂度O(n)。


本文的代码地址:


learn-algorithm

相关文章
|
20天前
|
传感器 并行计算 算法
【无人机编队】基于非支配排序遗传算法II NSGA-II高效可行的无人机离线集群仿真研究(Matlab代码实现)
【无人机编队】基于非支配排序遗传算法II NSGA-II高效可行的无人机离线集群仿真研究(Matlab代码实现)
|
6月前
|
JavaScript 前端开发 算法
JavaScript 中通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能,JS中排序算法的使用详解(附实际应用代码)
Array.sort() 是一个功能强大的方法,通过自定义的比较函数,可以处理各种复杂的排序逻辑。无论是简单的数字排序,还是多字段、嵌套对象、分组排序等高级应用,Array.sort() 都能胜任。同时,通过性能优化技巧(如映射排序)和结合其他数组方法(如 reduce),Array.sort() 可以用来实现高效的数据处理逻辑。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
6月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
7月前
|
算法 数据可视化 数据安全/隐私保护
一级倒立摆平衡控制系统MATLAB仿真,可显示倒立摆平衡动画,对比极点配置,线性二次型,PID,PI及PD五种算法
本课题基于MATLAB对一级倒立摆控制系统进行升级仿真,增加了PI、PD控制器,并对比了极点配置、线性二次型、PID、PI及PD五种算法的控制效果。通过GUI界面显示倒立摆动画和控制输出曲线,展示了不同控制器在偏转角和小车位移变化上的性能差异。理论部分介绍了倒立摆系统的力学模型,包括小车和杆的动力学方程。核心程序实现了不同控制算法的选择与仿真结果的可视化。
236 15
|
10月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
340 7
|
10月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
381 8
|
11月前
|
算法 搜索推荐 Java
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
基数排序是一种稳定的排序算法,通过将数字按位数切割并分配到不同的桶中,以空间换时间的方式实现快速排序,但占用内存较大,不适合含有负数的数组。
158 0
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
|
11月前
|
搜索推荐 Java Go
深入了解基数排序算法
深入了解基数排序算法
123 3
|
11月前
|
算法
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
115 0
|
11月前
|
存储 算法 搜索推荐
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
182 0

热门文章

最新文章