算法--基数排序

基数排序

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

思想

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

来源:

在老式的穿卡机中,利用卡片记录数据,每一个卡片中有多个列,每一列有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;//赋初值为0
			tempArray[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中数据在后面中都会为0
		for (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;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值