基数排序
2010-07-07 20:41
120 查看
基数排序是非比较排序算法,算法的时间复杂度是O(n).相比于快速排序的O(nlgn),从表面上看具有不小的优势.但事实上可能有些出入,因为基数排序的n可能具有比较大的系数K.因此在具体的应用中,应首先对这个排序函数的效率进行评估.
基数排序的主要思路是,将所有待比较数值(注意,必须是正整数)统一为同样的数位长度,数位较短的数前面补零.然后,从最低位开始,依次进行一次稳定排序(我们常用上一篇blog介绍的计数排序算法,因为每个位可能的取值范围是固定的从0到9).这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列.
比如这样一个数列排序:34258576356,以下描述演示了具体的排序过程(红色字体表示正在排序的数位)
第一次排序(个位):
342
576
356
058
第二次排序(十位):
342
356
058
576
第三次排序(百位):
058
342
356
576
结果:58342356576
两个问题:
为什么要从低位开始向高位排序?
如果要从高位排序,那么次高位的排序会影响高位已经排好的大小关系.在数学中,数位越高,数位值对数的大小的影响就越大.从低位开始排序,就是对这种影响的排序.数位按照影响力从低到高的顺序排序,数位影响力相同则比较数位值.
为什么同一数位的排序子程序要使用稳定排序?
稳定排序的意思是指,待排序相同元素之间的相对前后关系,在各次排序中不会改变.比如实例中具有十位数字5的两个数字58和356,在十位排序之前356在58之前,在十位排序之后,356依然在58之前.
稳定排序能保证,上一次的排序成果被保留,十位数的排序过程能保留个位数的排序成果,百位数的排序过程能保留十位数的排序成果.
算法的C#实现(综合了计数排序算法作为数位内排序算法):
这个算法的难度在于分离数位,将分离出的数位代表原元素的代表,用作计数排序.但是分离数位不能脱离原来的数字,计数排序的结果,还是要移动原元素.
注意计数排序的元素数值与位置的联系,引申到基数排序的从元素得到中间值然后与位置的联系.
测试程序如下:
基数排序的主要思路是,将所有待比较数值(注意,必须是正整数)统一为同样的数位长度,数位较短的数前面补零.然后,从最低位开始,依次进行一次稳定排序(我们常用上一篇blog介绍的计数排序算法,因为每个位可能的取值范围是固定的从0到9).这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列.
比如这样一个数列排序:34258576356,以下描述演示了具体的排序过程(红色字体表示正在排序的数位)
第一次排序(个位):
342
576
356
058
第二次排序(十位):
342
356
058
576
第三次排序(百位):
058
342
356
576
结果:58342356576
两个问题:
为什么要从低位开始向高位排序?
如果要从高位排序,那么次高位的排序会影响高位已经排好的大小关系.在数学中,数位越高,数位值对数的大小的影响就越大.从低位开始排序,就是对这种影响的排序.数位按照影响力从低到高的顺序排序,数位影响力相同则比较数位值.
为什么同一数位的排序子程序要使用稳定排序?
稳定排序的意思是指,待排序相同元素之间的相对前后关系,在各次排序中不会改变.比如实例中具有十位数字5的两个数字58和356,在十位排序之前356在58之前,在十位排序之后,356依然在58之前.
稳定排序能保证,上一次的排序成果被保留,十位数的排序过程能保留个位数的排序成果,百位数的排序过程能保留十位数的排序成果.
算法的C#实现(综合了计数排序算法作为数位内排序算法):
publicstaticint[]RadixSort(int[]ArrayToSort,intdigit)
{
//lowtohighdigit
for(intk=1;k<=digit;k++)
{
//temparraytostorethesortresultinsidedigit
int[]tmpArray=newint[ArrayToSort.Length];
//temparrayforcountingsort
int[]tmpCountingSortArray=newint[10]{0,0,0,0,0,0,0,0,0,0};
//CountingSort
for(inti=0;i<ArrayToSort.Length;i++)
{
//splitthespecifieddigitfromtheelement
inttmpSplitDigit=ArrayToSort[i]/(int)Math.Pow(10,k-1)-(ArrayToSort[i]/(int)Math.Pow(10,k))*10;
tmpCountingSortArray[tmpSplitDigit]+=1;
}
for(intm=1;m<10;m++)
{
tmpCountingSortArray[m]+=tmpCountingSortArray[m-1];
}
//outputthevaluetoresult
for(intn=ArrayToSort.Length-1;n>=0;n--)
{
inttmpSplitDigit=ArrayToSort
/(int)Math.Pow(10,k-1)-(ArrayToSort
/(int)Math.Pow(10,k))*10;
tmpArray[tmpCountingSortArray[tmpSplitDigit]-1]=ArrayToSort
;
tmpCountingSortArray[tmpSplitDigit]-=1;
}
//copythedigit-insidesortresulttosourcearray
for(intp=0;p<ArrayToSort.Length;p++)
{
ArrayToSort[p]=tmpArray[p];
}
}
returnArrayToSort;
}
这个算法的难度在于分离数位,将分离出的数位代表原元素的代表,用作计数排序.但是分离数位不能脱离原来的数字,计数排序的结果,还是要移动原元素.
注意计数排序的元素数值与位置的联系,引申到基数排序的从元素得到中间值然后与位置的联系.
测试程序如下:
staticvoidMain(string[]args)
{
int[]ary=newint[]{332,653,632,755,433,722,48};
int[]res=RadixSort(ary,3);
foreach(intvrinres)
{
Console.Write(vr.ToString()+"");
}
Console.ReadLine();
}
相关文章推荐
- 数据结构 排序 基数排序
- 排序——基数排序
- [C] - 希尔排序,非递归的快速排序,递归的快速排序,堆排序,归并排序,基数排序
- 基数排序
- 基数排序
- 算法导论8-3(a)习题解答(基数排序)
- 分配排序---箱排序,基数排序与桶排序及排序选择方法
- 基数排序
- C++基数排序(包含计数排序)
- 基数排序
- 程序员必知的8大排序(四)-------归并排序,基数排序(java实现)
- 【排序算法】基数排序(RadixSort)
- 三种线性排序算法 计数排序、桶排序与基数排序
- 基数排序
- 《算法导论》CLRS算法C++实现(六)P100 基数排序
- 基数排序
- 【CLRS】《算法导论》读书笔记(三):计数排序(Counting sort)、基数排序(Radix sort)和桶排序(Bucket sort)
- 【算法学习】线性时间排序-计数排序、基数排序和桶排序详解与编程实现
- 基数排序
- 【算法导论】基数排序