news 2026/8/24 18:06:50

排序--07---基数排序

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
排序--07---基数排序

基数排序

定义:

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

原理:

  1. 将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。
  2. 然后,从最低位开始,依次进行一次排序。 这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。

举例图文说明:

将数组{ 53, 3, 542, 748, 14, 214};使用基数排序,进行升序排序



代码实现1

将数组{ 53, 3, 542, 748, 14, 214};使用基数排序,进行升序排序

过程分析:

首先按上图分析,分成3轮,过程推导

  • 第1轮(针对每个元素的个位进行排序处理)
  • 第2轮(针对每个元素的十位进行排序处理)
  • 第3轮(针对每个元素的百位进行排序处理)

推导过程代码

importjava.util.Arrays;publicclassRadixSort{publicstaticvoidmain(String[]args){intarr[]={53,3,542,748,14,214};System.out.println("基数排序后 "+Arrays.toString(arr));radixSort(arr);System.out.println("基数排序后 "+Arrays.toString(arr));}//基数排序方法publicstaticvoidradixSort(int[]arr){//定义一个二维数组,表示10个桶, 每个桶就是一个一维数组//说明//1. 二维数组包含10个一维数组//2. 为了防止在放入数的时候,数据溢出,则每个一维数组(桶),大小定为arr.length//3. 名明确,基数排序是使用空间换时间的经典算法int[][]bucket=newint[10][arr.length];//为了记录每个桶中,实际存放了多少个数据,我们定义一个一维数组来记录各个桶的每次放入的数据个数//可以这里理解//比如:bucketElementCounts[0] , 记录的就是 bucket[0] 桶的放入数据个数int[]bucketElementCounts=newint[10];//第1轮(针对每个元素的个位进行排序处理)for(intj=0;j<arr.length;j++){//取出每个元素的个位的值intdigitOfElement=arr[j]/1%10;//放入到对应的桶中bucket[digitOfElement][bucketElementCounts[digitOfElement]]=arr[j];bucketElementCounts[digitOfElement]++;}//按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数组)intindex=0;//遍历每一桶,并将桶中是数据,放入到原数组for(intk=0;k<bucketElementCounts.length;k++){//如果桶中,有数据,我们才放入到原数组if(bucketElementCounts[k]!=0){//循环该桶即第k个桶(即第k个一维数组), 放入for(intl=0;l<bucketElementCounts[k];l++){//取出元素放入到arrarr[index++]=bucket[k][l];}}//第l轮处理后,需要将每个 bucketElementCounts[k] = 0 !!!!bucketElementCounts[k]=0;}System.out.println("第1轮,对个位的排序处理 arr ="+Arrays.toString(arr));//==========================================//第2轮(针对每个元素的十位进行排序处理)for(intj=0;j<arr.length;j++){// 取出每个元素的十位的值intdigitOfElement=arr[j]/10%10;//748 / 10 => 74 % 10 => 4// 放入到对应的桶中bucket[digitOfElement][bucketElementCounts[digitOfElement]]=arr[j];bucketElementCounts[digitOfElement]++;}// 按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数组)index=0;// 遍历每一桶,并将桶中是数据,放入到原数组for(intk=0;k<bucketElementCounts.length;k++){// 如果桶中,有数据,我们才放入到原数组if(bucketElementCounts[k]!=0){// 循环该桶即第k个桶(即第k个一维数组), 放入for(intl=0;l<bucketElementCounts[k];l++){// 取出元素放入到arrarr[index++]=bucket[k][l];}}//第2轮处理后,需要将每个 bucketElementCounts[k] = 0 !!!!bucketElementCounts[k]=0;}System.out.println("第2轮,对个位的排序处理 arr ="+Arrays.toString(arr));//第3轮(针对每个元素的百位进行排序处理)for(intj=0;j<arr.length;j++){// 取出每个元素的百位的值intdigitOfElement=arr[j]/100%10;// 748 / 100 => 7 % 10 = 7// 放入到对应的桶中bucket[digitOfElement][bucketElementCounts[digitOfElement]]=arr[j];bucketElementCounts[digitOfElement]++;}// 按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数组)index=0;// 遍历每一桶,并将桶中是数据,放入到原数组for(intk=0;k<bucketElementCounts.length;k++){// 如果桶中,有数据,我们才放入到原数组if(bucketElementCounts[k]!=0){// 循环该桶即第k个桶(即第k个一维数组), 放入for(intl=0;l<bucketElementCounts[k];l++){// 取出元素放入到arrarr[index++]=bucket[k][l];}}//第3轮处理后,需要将每个 bucketElementCounts[k] = 0 !!!!bucketElementCounts[k]=0;}System.out.println("第3轮,对个位的排序处理 arr ="+Arrays.toString(arr));}}

最终排序代码:

importjava.util.Arrays;publicclassRadixSort01{publicstaticvoidmain(String[]args){intarr[]={53,3,542,748,14,214};System.out.println("基数排序后 "+Arrays.toString(arr));radixSort(arr);System.out.println("基数排序后 "+Arrays.toString(arr));}//基数排序方法publicstaticvoidradixSort(int[]arr){//根据前面的推导过程,我们可以得到最终的基数排序代码//1. 得到数组中最大的数的位数intmax=arr[0];//假设第一数就是最大数for(inti=1;i<arr.length;i++){if(arr[i]>max){max=arr[i];}}//得到最大数是几位数intmaxLength=(max+"").length();//定义一个二维数组,表示10个桶, 每个桶就是一个一维数组//说明//1. 二维数组包含10个一维数组//2. 为了防止在放入数的时候,数据溢出,则每个一维数组(桶),大小定为arr.length//3. 名明确,基数排序是使用空间换时间的经典算法int[][]bucket=newint[10][arr.length];//为了记录每个桶中,实际存放了多少个数据,我们定义一个一维数组来记录各个桶的每次放入的数据个数//可以这里理解//比如:bucketElementCounts[0] , 记录的就是 bucket[0] 桶的放入数据个数int[]bucketElementCounts=newint[10];//这里我们使用循环将代码处理for(inti=0,n=1;i<maxLength;i++,n*=10){//(针对每个元素的对应位进行排序处理), 第一次是个位,第二次是十位,第三次是百位..for(intj=0;j<arr.length;j++){//取出每个元素的对应位的值intdigitOfElement=arr[j]/n%10;//放入到对应的桶中bucket[digitOfElement][bucketElementCounts[digitOfElement]]=arr[j];bucketElementCounts[digitOfElement]++;}//按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数组)intindex=0;//遍历每一桶,并将桶中是数据,放入到原数组for(intk=0;k<bucketElementCounts.length;k++){//如果桶中,有数据,我们才放入到原数组if(bucketElementCounts[k]!=0){//循环该桶即第k个桶(即第k个一维数组), 放入for(intl=0;l<bucketElementCounts[k];l++){//取出元素放入到arrarr[index++]=bucket[k][l];}}//第i+1轮处理后,需要将每个 bucketElementCounts[k] = 0 !!!!bucketElementCounts[k]=0;}System.out.println("第"+(i+1)+"轮,对个位的排序处理 arr ="+Arrays.toString(arr));}}}

得到最大数是几位数
int maxLength = (max + “”).length();

代码实现 2

  • 确认最大数的位数后,没轮排序,又用到计数排序的原理

importjava.util.Arrays;publicclassMultiKeyRadixSort{publicstaticvoidradixSort(int[]data){System.out.println("开始排序:");//1. 得到数组中最大的数的位数intmax=data[0];//假设第一数就是最大数for(inti=1;i<data.length;i++){if(data[i]>max){max=data[i];}}//得到最大数是几位数intmaxLength=(max+"").length();//待排序数组的长度intarrayLength=data.length;int[]temp=newint[arrayLength];int[]buckets=newint[10];for(inti=0,rate=1;i<maxLength;i++){// 重置count数组,开始统计第二个关键字Arrays.fill(buckets,0);// 当data数组的元素复制到temp数组中进行缓存System.arraycopy(data,0,temp,0,arrayLength);for(intj=0;j<arrayLength;j++){intsubKey=(temp[j]/rate)%10;buckets[subKey]++;}for(intj=1;j<10;j++){buckets[j]=buckets[j]+buckets[j-1];}for(intm=arrayLength-1;m>=0;m--){intsubKey=(temp[m]/rate)%10;data[--buckets[subKey]]=temp[m];}System.out.println("对"+rate+"位上子关键字排序:"+java.util.Arrays.toString(data));rate*=10;}}publicstaticvoidmain(String[]args){int[]data={1100,192,221,12,13};System.out.println("排序之前:\n"+java.util.Arrays.toString(data));radixSort(data);System.out.println("排序之后:\n"+java.util.Arrays.toString(data));}}

注意: --buckets[index] 会改变数组中的值

publicclassTest01{publicstaticvoidmain(String[]args){int[]buckets=newint[]{1,2,3};System.out.println(Arrays.toString(buckets));for(inti=0;i<buckets.length;i++){inta=--buckets[i];System.out.println("a= "+a);System.out.println("=========");}System.out.println(Arrays.toString(buckets));}}

基数排序总结:

  1. 基数排序是对传统桶排序的扩展,速度很快
  2. 基数排序是经典的空间换时间的方式,占用内存很大,当对海量数据排序时,容易造OutOfMemoryError
  3. 基数排序时稳定的
  4. 有负数的数组,我们不用基数排序来进行排序,如果要支持负数,参考:
    https://code.i-harness.com/zh-CN/q/e98fa9

基数排序是经典的空间换时间的方法,占用内存很大.海量数据容易OOM

算法分析

  • 最佳情况:T(n) = O(n * k)
  • 最差情况:T(n) = O(n * k)
  • 平均情况:T(n) = O(n * k) 稳定
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/24 18:05:51

Vue与React深度对比:从设计哲学到实战选型全解析

1. 项目概述&#xff1a;为什么我们需要对比Vue和React&#xff1f; 在任何一个前端开发者的成长路径上&#xff0c;几乎都绕不开一个经典的“选择题”&#xff1a;Vue和React&#xff0c;我该选哪个&#xff1f;这个问题就像问一个厨师&#xff0c;中餐和西餐哪个更好一样&…

作者头像 李华
网站建设 2026/8/24 18:05:32

开源桌面分区工具NoFences:5分钟整理桌面

开源桌面分区工具NoFences&#xff1a;5分钟整理桌面 【免费下载链接】NoFences &#x1f6a7; Open Source Stardock Fences alternative 项目地址: https://gitcode.com/gh_mirrors/no/NoFences 下午三点&#xff0c;你要找 Git 的快捷方式&#xff0c;得从一排游戏图…

作者头像 李华
网站建设 2026/8/24 18:04:10

Android Camera YUV转RGB性能优化:从C2D瓶颈到GPU零拷贝方案

1. 项目概述&#xff1a;当Camera的YUV数据遇上C2D转换瓶颈在Android应用开发中&#xff0c;尤其是涉及实时图像处理、AR滤镜、视频通话或者计算机视觉的场景&#xff0c;从Camera获取的原始YUV数据到最终屏幕显示的RGB数据&#xff0c;这条流水线是性能的命脉。最近在优化一个…

作者头像 李华
网站建设 2026/8/24 18:01:30

OPC UA设置事件节点

参考链接&#xff1a;Question about Python OPCUA session timeout and client. import asyncio, json from asyncua import Client, ua, Node from asyncua.common.events import Event from datetime import datetime####################################################…

作者头像 李华
网站建设 2026/8/24 17:59:01

智能体自我进化新范式:协同进化与经验蒸馏技术解析

1. 项目概述&#xff1a;从静态执行到动态进化的智能体新范式最近在智能体&#xff08;Agent&#xff09;领域&#xff0c;一个名为“Mem$^2$Evolve”的概念讨论度很高。简单来说&#xff0c;它探讨的是一种能让智能体像生物一样&#xff0c;在运行过程中不断自我进化、自我完善…

作者头像 李华