基数排序是非比较排序算法,算法的时间复杂度是O(n). 相比于快速排序的O(nlgn),从表面上看具有不小的优势.但事实上可能有些出入,因为基数排序的n可能具有比较大的系数K.因此在具体的应用中,应首先对这个排序函数的效率进行评估.
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã基数排序的主要思路是,将所有待比较数值(
注意,必须是正整数)统一为同样的数位长度,数位较短的数前面补零. 然后, 从最低位开始, 依次进行一次
稳定排序(我们常用上一篇blog介绍的计数排序算法, 因为
每个位可能的取值范围是固定的从0到9).这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列.
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã比如这样一个数列排序: 342 58 576 356, 以下描述演示了具体的排序过程(红色字体表示正在排序的数位)
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã第一次排序(个位):
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã3 4
2ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã5 7
6ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã3 5
6ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã0 5
8ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã第二次排序(十位):
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã3
4 2
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã3
5 6
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã0
5 8
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã5
7 6
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã第三次排序(百位):
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã0 5 8
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã3 4 2
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã3 5 6
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã5 7 6
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã结果: 58 342 356 576
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã两个问题:
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã 如果要从高位排序, 那么次高位的排序会影响高位已经排好的大小关系. 在数学中, 数位越高,数位值对数的大小的影响就越大.从低位开始排序,就是对这种影响的排序. 数位按照影响力从低到高的顺序排序, 数位影响力相同则比较数位值.ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã
稳定排序的意思是指, 待排序相同元素之间的相对前后关系,在各次排序中不会改变.比如实例中具有十位数字5的两个数字58和356, 在十位排序之前356在58之前,在十位排序之后, 356依然在58之前.ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã
稳定排序能保证,上一次的排序成果被保留,十位数的排序过程能保留个位数的排序成果,百位数的排序过程能保留十位数的排序成果.ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã
算法的C#实现(综合了计数排序算法作为数位内排序算法):
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kãpublic static int[] RadixSort(int[] ArrayToSort, int digit){ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã //low to high digitü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã for (int k = 1; k <= digit; k++)ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã {ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã //temp array to store the sort result inside digitü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã int[] tmpArray = new int[ArrayToSort.Length];ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã //temp array for countingsortü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã int[] tmpCountingSortArray = new int[10]{0,0,0,0,0,0,0,0,0,0};ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã //CountingSortü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã for (int i = 0; i < ArrayToSort.Length; i++)ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã {ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã //split the specified digit from the elementü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã int tmpSplitDigit = ArrayToSort/(int)Math.Pow(10,k-1) - (ArrayToSort/(int)Math.Pow(10,k))*10;ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã tmpCountingSortArray[tmpSplitDigit] += 1;ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã }ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã for (int m = 1; m < 10; m++)ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã {ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã tmpCountingSortArray[m] += tmpCountingSortArray[m - 1];ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã }ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã //output the value to resultü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã for (int n = ArrayToSort.Length - 1; n >= 0; n--)ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã {ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã int tmpSplitDigit = ArrayToSort[n] / (int)Math.Pow(10,k - 1) - (ArrayToSort[n]/(int)Math.Pow(10,k)) * 10;ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã tmpArray[tmpCountingSortArray[tmpSplitDigit]-1] = ArrayToSort[n];ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã tmpCountingSortArray[tmpSplitDigit] -= 1;ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã }ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã //copy the digit-inside sort result to source arrayü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã for (int p = 0; p < ArrayToSort.Length; p++)ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã {ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã ArrayToSort[p] = tmpArray[p];ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã }ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã }ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã return ArrayToSort;}ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kãü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã这个算法的难度在于分离数位,将分离出的数位代表原元素的代表, 用作计数排序.但是分离数位不能脱离原来的数字,计数排序的结果,还是要移动原元素.ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã注意计数排序的元素数值与位置的联系,引申到基数排序的从元素得到中间值然后与位置的联系.ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kãü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã测试程序如下:
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kãstatic void Main(string[] args){ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã int[] ary = new int[] { 332, 653, 632, 755, 433, 722, 48 }; ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã int[] res = RadixSort(ary, 3); ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã foreach (int vr in res)ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã {ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã Console.Write(vr.ToString() + " ");ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã }ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã Console.ReadLine();ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã}ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã
ü1ÝÆ¤ç¥©www.netcsharp.cnô2¦Å
ð=Kã