算法--基数排序

来源:互联网 发布:othello棋 uct算法 编辑:程序博客网 时间:2024/04/29 21:26

基数排序

基数排序是一种非比较型的排序算法。

思想

将整数分割成不同的数字,再对每一位进行比较,先从各位开始,一次往上走,直到某一位都相等。它是在一种老式穿卡机上的算法。当然在典型的顺序随机存取计算机上,又是采用基数排序算法对多个关键字域进行排序。例如我们对生日的排序,不仅可以从年份开始,也可以从日期开始。

来源:

在老式的穿卡机中,利用卡片记录数据,每一个卡片中有多个列,每一列有12个位置,可以在任一个位置进行打卡,然后将卡片进行排序。但是我们一次只能看到卡片中的一列,当然基于原来的思想是从高位开始排序,与桶排序一样,将数据进行分割,但好似我们知道在桶排序中我们有一个存储索引的数组。在这里我们还要再添加另外的卡片进行数据的记录,显然是不合理的。这个时候只能从低位开始往高位进行排序,当高位的数字一样,依旧保持着上次的排序结果。

模拟:

假如有几个数字:329457657839436720355。那么排序结果为:每一列为一次运行结果

 329

720

720

329

457

355

329

355

657

436

436

436

839

457

839

457

436

657

355

657

720

329

457

720

355

839

657

839

效能分析:

若给定nd位数,每一个数位可以去k中可能的值。如果所用的稳定排序需要(n+k)的时间,那么技术排序算法能够以d(n+k)的时间正确的对这些数进行排序。为什么会有(n+k)呢,这个让我们记起比较排序,貌似都是n(lgn)的情况,是的,计数排序,因为每一位数我们都是有范围的,若是10进制的话,不过最大的是0-9的范围。对辅助数组赋初值为k,对辅助数组计算元素出现次数为n

与快速排序的分析:

基数排序看上去似乎要比快速排序的平均情况好一些。计数排序作为中间稳定排序的基数排序不是在位的排序,而快排就可以做到。快排比基数排序更为有效利用硬件缓存。所以当内存比较珍贵的时候还是用快排。并且,在每一遍处理的时间要比快排长。另外它的隐含因子就是d(n+k)前面的数值并不确定。我们依旧不能够知道哪个效率会高一些。

代码:

struct RadixTempNode{public:int bitNum;//元素出现的次数int bitLocation;//最后这个元素所在的位置RadixTempNode(){bitNum=0;bitLocation=0;}};


 

template<class T>T* RadixList<T>::RadixSort(T *radixArray,int length){//思想:将所有的待比较整数统一为有相同位数长度,数位较短的前面补零。//然后从地位到高位依次进行一次排序。在每个位上可以采用效率较好的排序算法//这里我们采用的是计数排序,但是计数排序不是稳定的排序算法,于是我们要进行改进RadixTempNode tempArray[10];//每一位都是0-9,这里假设是10进制的情况T *resultArray=new T [length];//排序后的数组bool bitPos=true;int modeData=10;int bitData=0;while(bitPos)//当位数存在时,下面将利用到的是计数排序    {bitPos=false;for(int i=0;i<10;i++)    {    tempArray[i].bitNum=0;//赋初值为0tempArray[i].bitLocation=0;    }for (int i=0;i<length;i++){*(resultArray+i)=0;//清空结果数组}for(int i=0;i<length;i++){   bitData=*(radixArray+i)%modeData/(modeData/10);//得到位数上的值if (bitData!=0){bitPos=true;}tempArray[bitData].bitNum+=1; //tempArray中索引就是余数,也就是要排序的数值,                              //而tempArray中的值为这个排序的数出现的次数}if (!bitPos){break;}tempArray[0].bitLocation=tempArray[0].bitNum;//加一个存储空间保证稳定算法for (int j=1;j<10;j++){tempArray[j].bitLocation=tempArray[j].bitNum+tempArray[j-1].bitLocation;//所在位置}for (int k=0;k<length;k++){   bitData=*(radixArray+k)%modeData/(modeData/10);//计数排序并不是稳定的排序算法,因此后面要改进//找到在temArray中索引为RadixArray[index]的在的数值,这个数值就是在resultArray中的位置*(resultArray+tempArray[bitData].bitLocation-tempArray[bitData].bitNum)=*(radixArray+k);tempArray[bitData].bitNum-=1;//这里必须减一否则会一直覆盖原来位置上的值,而其它的地方值却一直为0}cout<<"结果为:"<<endl;for (int i=0;i<length;i++){cout<<*(resultArray+i)<<" ";}cout<<endl;modeData*=10;//radixArray=resultArray;//若仅仅是这一条语句,没有后面的,这个时候是指针赋值,而resultArray中数据在后面中都会为0for (int index=0;index<length;index++){*(radixArray+index)=*(resultArray+index);}}return radixArray;}void RadixSortTest(){int testArray[]={329,457,657,839,436,720,355};cout<<"初始数组为:"<<endl;for(int i=0;i<7;i++){cout<<*(testArray+i)<<" ";}cout<<endl;RadixList<int>*radixSort=new RadixList<int>();int *resultArray=radixSort->RadixSort(testArray,7);cout<<"基数排序后的结果为:"<<endl;for (int i=0;i<7;i++){cout<<*(resultArray+i)<<" ";}cout<<endl;}


 

运行结果如上所示

小结:

1、作为非比较的排序算法,基数排序有点类似桶排序,不过一个是从高位,一个是从地位进行。

2、记得在对tempArray中赋值时与原来的计数不同,之前的计数是tempArray[indec]+=tempArray[i-1].在这里因为我们使用了一个结构体保证稳定性,所以是忽视了0位置上的值。所以tempArray[0].bitLocation=tempArray[0].bitNum;。

3、其核心代码为:*(resultArray+tempArray[bitData].bitLocation-tempArray[bitData].bitNum)=*(radixArray+ktempArray[bitData].bitNum-=1;

原创粉丝点击