概念介绍:
基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。 (来自百度百科)
排序原理:
基数排序是非比较排序的一种,它分为两种:高位优先(MSD),低位优先(LSD)。其原理都是按位来进行哈希操作。本文描述的是低位优先操作,大致思想是:1.在一堆数组中首先找到最大值;2.确定最大值的位数;3.在进行入桶操作。入桶操作是将元素按照个位,十位,百位...从小到大的顺序依次入桶,个位入桶操作结束后进行排序,排序过程结束后,清空桶,再按元素十位由小到大的顺序入桶,在排序... ...以此类推,直到将最大元素的所有位数全部排好,基数排序过程结束。
排序过程:
例如:int arr[] = {10,3,26,9,8,30,15,18,211,256,341};存在这么一堆数组,首先知道数组中最大值是341,是三位数,申请10个桶大小的空间(0-9 一共10个数字),再按照个位,十位,百位一次入桶,排序。
按上图我们可以看出首先进行按个位进行排序,申请一块10大小的空间
数组内元素按顺序入桶,将数组内元素按照个位大小排序,排序结束后再返回原数组,数组由:
int arr[] = {10,3,26,9,8,30,15,18,211,256,341};
变成:
int arr[] = {10,30,211,341,3,15,26,256,8,18,9};
数组内元素按顺序入桶,再将数组中元素按十位大小进行排序,排序结束后再返回原数组:
数组由:
int arr[] = {10,30,211,341,3,15,26,256,8,18,9};
变成:
int arr[]={3,8,9,10,211,15,18,23,30,341,256};
数组内元素按顺序入桶,将数组中元素按百位大小进行排序,排序结束后再返回原数组:
数组由:
int arr[]={3,8,9,10,211,15,18,23,30,341,256};
变成:
int arr[]={3,8,9,10,15,18,23,30,211,256,341};
基数排序算法的实现:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct node
{
int nValue;
struct node* pNext;
}Radix;
void SORT(int arr[],int nlen,int nNum,Radix**pRadix)
{
//算出最大值是几位数 个位是1 十位是2 百位是3 ...
int nBase = 1;
while(nNum>1)
{
nNum--;
nBase *= 10;
}
//根据基数入桶 使用尾添加的方法
int i ;
int Indix;
Radix *Temp = NULL;
Radix *pNode = NULL;
for(i = 0;i<nlen;i++)
{
Indix = arr[i]/nBase%10;
Temp = (Radix*)malloc(sizeof(Radix));
Temp->nValue = arr[i];
Temp->pNext = NULL;
//添加
if(pRadix[Indix] == NULL)//如果桶是空 直接插入
{
pRadix[Indix] = Temp;
}
else//若不是空
{
pNode = pRadix[Indix];//遍历链表
while(pNode ->pNext != NULL)
{
pNode = pNode->pNext;
}//在链表最后一个元素的后面插入新元素
pNode->pNext = Temp;
}
}
//数据放回原来的数组内
int j = 0;
for(i = 0;i<10;i++)
{
pNode = pRadix[i];
while(pNode)
{
//小链表遍历 按顺序放入数组
arr[j] = pNode->nValue;
j++;
pNode = pNode->pNext;
}
}
//清除 小链表
for( i = 0;i<10;i++)
{
pNode = pRadix[i];
while(pNode)
{
Temp = pNode;
pNode = pNode->pNext;
free(Temp);
Temp = NULL;
}
}
//切记要添加完以后要清空桶
memset(pRadix,0,sizeof(Radix*)*10);
}
void RADIXSORT(int arr[],int len)
{
int i;
if(arr == NULL || len <=0 ) return ;
//找到最大值
int nMax = arr[0];//最大值
for(i = 1;i< len; i++)
{
if(arr[i] > nMax)
{nMax = arr[i];}
}
int base = 1;//位数
while(nMax)
{
base++;
nMax /= 10;
}
//如桶前,申请桶,并且当参数将桶传进排序函数
//申请的空间内放的是结构体,并且最多就(0-9)10个元素
Radix** pRadix = NULL;
pRadix = (Radix**)malloc(sizeof(Radix*)*10);
// 注意要清空桶,不然会对结果有影响
memset(pRadix,0,sizeof(Radix*)*10);
//处理各个位数 个位 十位 百位... ...
for(int i = 1;i<base;i++)
{
//排序函数
SORT(arr,len,i,pRadix);
}
//释放空间
free(pRadix);
pRadix = NULL;
}
void Print(int arr[],int nLength)
{
int i;
for(i = 0;i<nLength;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = {10,3,26,9,8,30,15,18,211,256,341};
printf("原来的:");
Print(arr,sizeof(arr)/sizeof(arr[0]));
RADIXSORT(arr,sizeof(arr)/sizeof(arr[0]));
printf("排序后的:");
Print(arr,sizeof(arr)/sizeof(arr[0]));
复杂度分析
在基数排序中,因为没有比较操作,所以在复杂上,最好的情况与最坏的情况在时间上是一致的。因此无论是最好,最坏还是平均复杂度都是O(d * (n + r))。其中,d 为位数,r 为基数,n 为原数组个数。 空间复杂度O(n+r)。是稳定的。