基数排序的C++实现(解析)

来源:互联网 发布:浙江计价软件 编辑:程序博客网 时间:2024/05/16 17:26
基数排序(Radix sort)是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。基数排序的发明可以追溯到1887年赫尔曼·何乐礼在打孔卡片制表机(Tabulation Machine)上的贡献。时间复杂度是 O(k·n),其中n是排序元素个数,k是数字位数。——来自维基百科
空间复杂度为O(B),其中B为基数Base,如10或16等,不是一个稳定排序。
维基百科上有C++实现的代码,够简练,看了一段时间才看明白,在每次基于各个数位上的数字散列和合并的时候,用的方式够巧妙,是我没想出来的!特在此处贴出来,然后解释之~

我仿着维基百科给的C++代码,实现如下:

#include <iostream>#include <cstring>#include <ctime>using namespace std;struct Num{int v;Num *next;Num(){next=0;}};void sort(int *arr,int len){const int RADIX=10;//以10为基进行排序int tmp;Num *topBox[RADIX];//桶中最新添加进去的元素Num *bottomBox[RADIX];//桶底元素for(int i=0;i<RADIX;++i){topBox[i]=bottomBox[i]=new Num;}//找最大值tmp=arr[0];for(int i=0;i<len;++i){if(tmp<arr[i])tmp=arr[i];}//计算最大值有多少个数位int digCnt=1;tmp/=RADIX;while(tmp){++digCnt;tmp/=RADIX;}//将数组转换成链表Num *head=new Num;Num *cur;cur=head;for(int i=0;i<len;++i){cur->next=new Num;cur->next->v=arr[i];cur=cur->next;}//开始基数排序int factor=1;for(int i=0;i<digCnt;++i){//散列for(cur=head->next;cur;cur=cur->next){tmp=(cur->v/factor)%RADIX;topBox[tmp]->next=cur;topBox[tmp]=topBox[tmp]->next;}//合并cur=head;for(int j=0;j<RADIX;++j){if(topBox[j]!=bottomBox[j]){cur->next=bottomBox[j]->next;cur=topBox[j];topBox[j]=bottomBox[j];}}//必须将最后一个数字的next赋值为NULL,否则导致链表形成环,导致再次"散列"时会死循环cur->next=0;//扩大因子,用于取下一个数字factor*=RADIX;}//使用链表给数组赋值cur=head->next;for(int i=0;i<len;++i,cur=cur->next){arr[i]=cur->v;}}void test(){int len=20;int *heap=new int[len];srand(time(0));for(int i=0;i<len;++i){heap[i]=rand()%10000;}cout<<"初始数组:"<<endl;printArray(heap,len);//mySort(heap,0,len-1);sort(heap,len);printArray(heap,len);delete heap;}

bottomBox数组不会变化,因为它存储的是每个“桶”的初始元素,而topBox数组一直在变化,因为它始终指向“桶”中最近被添加的数字,这是由"基数排序中的每个"桶"必须在链表尾部添加新的数字"决定的,链表的尾部,就是topBox(可以把这个"桶"想象成一个开口向下的倒着的桶~)。起始状态,bottomBox与topBox里的每个元素都是一样的,因为每个"桶"里都没有数字,随着散列的进行,有些"桶"里就被先后放入多个数字,此时topBox随之变化,使自己总是指向"桶"最顶部的数字,也就是最新被添加的那个数字。

散列完成之后,需要将本次的散列结果按“在数组中散列到的桶号”串联起来,用于下次散列,串联的时候,每个“桶”中,开始的元素由bottomBox存储,终止元素由topBox存储,而且,如果该“桶”是空的,那么bottomBox对应的值与topBox对应的值相等,反过来说:凡是bottomBox中与topBox对应值不相等的那个“桶”里肯定有数字串,这个串的起始数字由bottomBox存储,终止数字由topBox存储。很巧妙吧!



原创粉丝点击