基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数
基数排序 vs 计数排序 vs 桶排序
这三种排序算法都利用了桶的概念,但对桶的使用方法上有明显差异:
- 基数排序:根据元素的每位数字来分配桶;
- 计数排序:每个桶只存储单一键值;
- 桶排序:每个桶存储一定范围的数值;
基数排序动图演示
#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;
}
运行结果:
未排序前:126 36 76 198 65 172 107 3 53 60
总遍历位数:3,最小值:3,最大值:198
遍历位数1:
a[0]=3,a[0]-3=0
a[1]=53,a[1]-3=50
a[2]=65,a[2]-3=62
a[3]=126,a[3]-3=123
a[4]=36,a[4]-3=33
a[5]=76,a[5]-3=73
a[6]=107,a[6]-3=104
a[7]=198,a[7]-3=195
a[8]=60,a[8]-3=57
a[9]=172,a[9]-3=169
遍历位数10:
a[0]=3,a[0]-3=0
a[1]=107,a[1]-3=104
a[2]=126,a[2]-3=123
a[3]=36,a[3]-3=33
a[4]=53,a[4]-3=50
a[5]=60,a[5]-3=57
a[6]=65,a[6]-3=62
a[7]=172,a[7]-3=169
a[8]=76,a[8]-3=73
a[9]=198,a[9]-3=195
遍历位数100:
a[0]=3,a[0]-3=0
a[1]=36,a[1]-3=33
a[2]=53,a[2]-3=50
a[3]=60,a[3]-3=57
a[4]=65,a[4]-3=62
a[5]=76,a[5]-3=73
a[6]=107,a[6]-3=104
a[7]=126,a[7]-3=123
a[8]=172,a[8]-3=169
a[9]=198,a[9]-3=195
基数排序:3 36 53 60 65 76 107 126 172 198