基数排序(Radix sort)是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。基数排序的发明可以追溯到1887年赫尔曼·何乐礼在打孔卡片制表机(Tabulation Machine)上的贡献。
它是这样实现的:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
基数排序时对每一维进行调用子排序算法时要求这个子排序算法必须是稳定的。
基数排序与直觉相反:它是按照从底位到高位的顺序排序的。
伪代码:
RADIX-SORT(A,d)
1 for i <-- 1 to d
2 do use a stable sort to sort array A on digit i
引理8.3: 给定n个d位数,每一个数位可以取k种可能的值,如果所用稳定排序需要Θ(n+k)时间,基数排序能以Θ(d(n+k))的时间完成。
证明:如果采用计数排序这种稳定排序,那么每一遍处理需要时间Θ(n+k),一共需处理d遍,于是基数排序的运行时间为Θ(d(n+k))。当d为常数,k=O(n)时,有线性运行时间。
注:将关键字分成若干位方面,可以有一定的灵活性。
引理8.4:给定n个b位数和任何正整数r<=b,如果采用的稳定排序需要Θ(d(n+k))时间,则RADIX-SORT能在Θ((b/r)(n+2r))时间内正确地对这些数进行排序。
证明:对于一个r<=b,将每个关键字看成由d=b/r位组成的数,每一个数字都是(0~ -1)之间的一个整数,这样就可以采取计数排序。K= ,d=b/r,总的运行时间为Θ((b/r)(n+ ))。
对于给定的n值和b值,如何选择r值使得最小化表达式(b/r)(n+2r)。如果b< lgn,对于任何r<=b的值,都有(n+2r)=Θ(n),于是选择r=b,使计数排序的时间为Θ((b/b)(n+2b)) = Θ(n)。 如果b>lgn,则选择r=lgn,可以给出在某一常数因子内的最佳时间:当r=lgn时,算法复杂度为Θ(bn/lgn),当r增大到lgn以上时,分子 增大比分母r快,于是运行时间复杂度为Ω(bn/lgn);反之当r减小到lgn以下的时候,b/r增大,而n+ 仍然是Θ(n)。
以下引自麻省理工学院算法导论——笔记:
以下代码实例转自:http://www.docin.com/p-449224125.html
1 以下是用C++实现的基数排序代码:
2 #include <cstdio>
3 #include <cstdlib>
4 // 这个是基数排序用到的计数排序,是稳定的。
5 // pDigit是基数数组,nMax是基数的上限,pData是待排序的数组, nLen是待排序数组的元素个数
6 // 必须pDigit和pData的下标相对应的,即pDigit[1]对应pData[1]
7 int RadixCountingSort(int *pDigit, int nMax,int *pData,int nLen){
8 // 以下是计数排序
9 int *pCount = new int[nMax];
10 int *pSorted = new int[nLen];
11 int i,j;
12 for(i=0; i<nMax; ++i)
13 pCount[i] = 0;
14 for(i=0; i<nLen; ++i)
15 ++pCount[pDigit[i]];
16 for(i=1; i<nMax; ++i)
17 pCount[i] += pCount[i-1];
18 for(i=nLen-1; i>=0; --i){
19 --pCount[pDigit[i]];
20 pSorted[pCount[pDigit[i]]] = pData[i]; // z这里注意,是把待排序的数组赋值
21 }
22 for(i=0; i<nLen; ++i)
23 pData[i] = pSorted[i];
24 delete [] pCount;
25 delete [] pSorted;
26 return 1;
27 }
28 int RadixSort(int *pData, int nLen){
29 int *pDigit = new int[nLen]; // 申请存放基数(某个位数)的空间
30 int nRadixBase = 1;
31 bool flag = false;
32 while(!flag){
33 flag = true;
34 nRadixBase *= 10;
35 for(int i=0; i<nLen; ++i){
36 pDigit[i] = pData[i]%nRadixBase; // 求出某位上的数当做基数
37 pDigit[i] /= nRadixBase/10;
38 if(pDigit[i] > 0)
39 flag = false;
40 }
41 if(flag)
42 break;
43 RadixCountingSort(pDigit,10,pData,nLen);
44 }
45 delete[] pDigit;
46 return 1;
47 }
48 main()
49 {
50 int nData[10]={43,65,34,5,8,34,23,0,45,34};;
51 RadixSort(nData, 10);
52 printf("经排序后的数列是:\n");
53 for (int i = 0; i < 10; ++i)
54 printf("%d ", nData[i]);
55 printf("\n");
56 return 0;
57 }
posted on 2012-11-13 16:52
王海光 阅读(669)
评论(0) 编辑 收藏 引用 所属分类:
算法