基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。


(1)什么是基数排序?

1. 通过键值得各个位的值,将要排序的元素分配至一些桶中,达到排序的作用

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

3. 基数排序是桶排序的扩展


(2)实现原理

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


(3)LSD 基数排序动图演示

LSD 基数排序动图

LSD 基数排序动图


(4)C语言代码实现如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
//定义基数为10进制
#define radix 10
//交换数值
void swap(int *a,int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}
//打印数组
void printArray(char msg[],int arr[],int len){
    printf("%s:",msg);
    for (int i = 0; i < len; i++){
        printf("%d ", arr[i]);
    }
    printf("\n");
}
//基数排序
void radix_sort(int a[],int len){
    int maxvalue=a[0],minvalue=a[0];
    for(int x=0;x<len;x++){
        maxvalue=a[x]>maxvalue?a[x]:maxvalue;
        minvalue=a[x]<minvalue?a[x]:minvalue;
    }
    int* temp = (int*)malloc(len*sizeof(int));
    //获取最大位数
    int n=1;
    int d = maxvalue-minvalue;
    while(d>=10){
        d=d/10;
        n++;
    }
    printf("总遍历位数:%d,最小值:%d,最大值:%d\n",n,minvalue,maxvalue);
    //要获取的位
    int divide=1;
    for(int i=1;i<=n;i++){
        //初始化计数器
        int counter[radix]={0};
        for(int j=0;j<len;j++){
            //找出a[j]相对minvalue值的对应的位divide的值
            int pos = ((a[j]-minvalue)/divide)%radix;
            //a[j]换算成计数器数组下标pos并自增
            counter[pos]++;
        }
        //使用累加(counter[n]=counter[n]+counter[n-1],有点类似斐波那契数列)计算出元素所在位置,保证结果有序
        for(int j=1;j<10;j++){
            counter[j]=counter[j]+counter[j-1];
        }
        //倒序遍历数组a,可以保持结果稳定性
        for(int j=len-1;j>=0;j--){
            //将a[j]映射到计数器下标pos,counter[pos]就是a[j]在新数组的位置
            int pos=((a[j]-minvalue)/divide)%radix;
            //获取元素位置mappos,--counter[pos]:每放一个元素到数组temp,counter[pos]值自减,保证结果稳定有序
            int mappos=(--counter[pos]);
            temp[mappos]=a[j];
        }
        //把temp有序数组赋值给a
        for(int j=0;j<len;j++){
            a[j]=temp[j];
        }
        printf("遍历位数%d:\n",divide);
        for(int j=0;j<len;j++){
            printf("a[%d]=%d,a[%d]-%d=%d\n",j,a[j],j,minvalue,a[j]-minvalue);
        }
        printf("\n");
        //获取数值的下个位,比如个位数,下个是十位数
        divide=divide*radix;
    }
    free(temp);
}
int main()
{
    int len=10;
    int arr[len];
    srand((unsigned)time(NULL));
    //随机生成长度为"len"的数组
    for(int i=0;i<len;i++){
        arr[i]=rand()%200;
    }
    printArray("未排序前",arr,len);
    radix_sort(arr,len);
    printArray("基数排序",arr,len);
    //防止windows下控制台窗口闪退
    int s;
    scanf("%d",&s);
    return 0;
}

如果我们编译并运行上述程序,那么它应该产生以下结果:

未排序前:80 155 178 14 59 36 195 15 141 143 
总遍历位数:3,最小值:14,最大值:195
遍历位数1:
a[0]=14,a[0]-14=0
a[1]=155,a[1]-14=141
a[2]=195,a[2]-14=181
a[3]=15,a[3]-14=1
a[4]=36,a[4]-14=22
a[5]=178,a[5]-14=164
a[6]=59,a[6]-14=45
a[7]=80,a[7]-14=66
a[8]=141,a[8]-14=127
a[9]=143,a[9]-14=129

遍历位数10:
a[0]=14,a[0]-14=0
a[1]=15,a[1]-14=1
a[2]=36,a[2]-14=22
a[3]=141,a[3]-14=127
a[4]=143,a[4]-14=129
a[5]=155,a[5]-14=141
a[6]=59,a[6]-14=45
a[7]=178,a[7]-14=164
a[8]=80,a[8]-14=66
a[9]=195,a[9]-14=181

遍历位数100:
a[0]=14,a[0]-14=0
a[1]=15,a[1]-14=1
a[2]=36,a[2]-14=22
a[3]=59,a[3]-14=45
a[4]=80,a[4]-14=66
a[5]=141,a[5]-14=127
a[6]=143,a[6]-14=129
a[7]=155,a[7]-14=141
a[8]=178,a[8]-14=164
a[9]=195,a[9]-14=181

基数排序:14 15 36 59 80 141 143 155 178 195


作业:
1720 数据结构-基数排序
点赞(0)

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

Dotcpp在线编译      (登录可减少运行等待时间)