基数排序
基数排序(radix sort)则是属于“分配式排序”(distribution sort),基数排序法又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的比较性排序法。
效率分析:
时间效率:设待排序列为n个记录,d个关键码,关键码的取值范围为radix,则进行链式基数排序的时间复杂度为O(d(n+radix)),其中,一趟分配时间复杂度为O(n),一趟收集时间复杂度为O(n),共进行d趟分配和收集。 空间效率:需要2*radix个指向队列的辅助空间,以及用于静态链表的n个指针。
实现方法:
最高位优先(Most Significant Digit first)法,简称MSD法:先按k1排序分组,同一组中记录,关键码k1相等,再对各组按k2排序分成子组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各子组排序后。再将各组连接起来,便得到一个有序序列。 最低位优先(Least Significant Digit first)法,简称LSD法:先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。
基数排序一般仅是用于记录的关键字为整数类型的情况。
在已介绍的各种内部排序方法中,就所需要的计算时间来看,快速排序、归并排序、堆排序是很好的方法。但是,归并排序需要大小为n的辅助空间,快速排序需要一个栈。除了快速排序、堆排序、选择排序、希尔排序不稳定外,其它排序方法都是稳定的。
评价一个排序算法性能好坏的主要标准是它所需的计算时间和存储空间。影响计算时间的两个重要因素是比较关键字的次数和记录的移动次数。在实际应用中,究竟应该选用何种排序方法,取决于具体的应用和机器条件。
两个问题:
为什么要从低位开始向高位排序?
如果要从高位排序, 那么次高位的排序会影响高位已经排好的大小关系. 在数学中, 数位越高,数位值对数的大小的影响就越大.从低位开始排序,就是对这种影响的排序. 数位按照影响力从低到高的顺序排序,数位影响力相同则比较数位值.
为什么同一数位的排序子程序要使用稳定排序?
稳定排序的意思是指, 待排序相同元素之间的相对前后关系,在各次排序中不会改变.比如实例中具有十位数字5的两个数字58和356,在十位排序之前356在58之前,在十位排序之后, 356依然在58之前.
稳定排序能保证,上一次的排序成果被保留,十位数的排序过程能保留个位数的排序成果,百位数的排序过程能保留十位数的排序成果.
伪代码:
RADIX-SORT(A, d)
for i ← 1 to d
do use a stable sort to sort array A on digit i
在C++实现中,我使用了一个辅助的函数 int maxDigit(int* arr,int digit)来计算待排序数组中最大的数位,以使程序有更大的适用范围,不需要待排序的数字位数相同。
基数排序的算法很直观。在一个数组中,每个元素都有d位数字,其中第1位是最低位,第d位是最高位。依次判断每个位置的排序。基数排序需要另一种稳定的排序算法(stable sort)进行辅助。
完整代码:
#include <iostream>
using namespace std;
//定义基数,经研究选择2的次幂时,性能最好,比如2,4...1024
const static int Radix = 10;
//求数组中数字的最大位数
int maxBit(int arr[], int n)
{
int digit = 0;
int* temp = new int[n];//使用临时变量数组,防止修改原数组
for (int i = 0; i < n; i++)
temp[i] = arr[i];
for (int i = 0; i < n; i++)
{
int counter = 1;
while (temp[i] / 10 > 0)
{
counter++;
temp[i] /= 10;
}
if (digit < counter)
digit = counter;
}
delete[] temp;
return digit;
}
//获取第i位的值,比如1345,第三位是3
int get_part(int num,int i)
{
int p = (int)pow(Radix, i);
return (int)(num / p) % Radix;
}
//基数排序
void RadixSort(int arr[], int n)
{
int bits = maxBit(arr, n);
int *bucket = new int[n];//临时存储空间
int *count = new int[Radix];//值为k的数目,计数
//对每一位进行计数排序(稳定排序)
for (int i = 1; i <= bits; ++i)
{
for (int j = 0; j < Radix; ++j)
count[j] = 0;
for (int k = 0; k < n; ++k)
count[get_part(arr[k], i)]++;
for (int j = 1; j < Radix; ++j)
count[j] = count[j] + count[j - 1];
for (int j = n - 1; j >= 0; j--)
{
int index = get_part(arr[j], i);
bucket[count[index] - 1] = arr[j];
count[index]--;
}
for (int i = 0; i < n; i++)
arr[i] = bucket[i];
}
delete[] bucket;
delete[] count;
}
int main()
{
int a[] = { 22, 34, 95, 87, 56, 980, 12, 48 };
cout << "排序前的数组:";
for (int i = 0; i < 8; i++)
cout << a[i] << " ";
cout << endl;
RadixSort(a, 8);
cout << "排序后的数组:";
for (int i = 0; i < 8; i++)
cout << a[i] << " ";
cout << endl;
system("pause");
return 0;
}
基数排序算法的性能优化
http://blog.csdn.net/yutianzuijin/article/details/22876017
基数排序经典文档
http://www.cnblogs.com/Braveliu/archive/2013/01/21/2870201.html
版权声明:本文为博主原创文章,未经博主允许不得转载。