排序算法(4):基数排序

来源:互联网 发布:大神小的知错了txt下载 编辑:程序博客网 时间:2024/06/05 18:27

基数排序简介


摘自百度百科。
基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。

(透过资讯这种写法,让我觉得这一段的作者是中国台湾人!台湾是中国的!)

基数排序分两步:分配和收集。
1. 挂在队列上;
2. 把队列们都捋直了……

对数组进行基数排序


可以全部都用数组去实现。我先借助STL的队列实现。

基于队列


为了快速开发基数排序算法,我使用了STL的queue和vector。
vector的每个元素,都是一个queue。vector一共10个元素,分别代表0~9。
为了方便起见,先认为所有的待排序的数都是非负数
为了好写,可能多开了一些临时变量。也许空间占了很多。以后再优化。
养成好习惯:把任务拆解开来。先写算法步骤。


#define N 10 // x的大小
radixSort(int x[]) {
// 1. 获取x中最大的关键字位数,为maxDigit。当前维数currentDigit = 1(代表按个位、十位、百位……的顺序来写)。
// 2. 对于每一个x[i],从右往左看第currentDigit位,把x[i]放入vector[currentDigit]的queue中
// 3. 把vector捋直(出队)。
// 4. 用个临时数组B,存按个位排好的x。
// 5. 把B赋值到x中。currentDigit++。
// 6. 重复2-5,直到currentDigit>maxDigit。
}

/************************************************************************//* 基数排序用stl的队列加以辅助*//************************************************************************/#include <iostream>#include <vector>#include <queue>#define N 12using namespace std;void showArray(int *x,int size) {for (int i = 0;i<size;i++){cout<<x[i]<<" ";}cout<<"\n";}// 获取最大位数int getMaxDigit(int x[]){int maxNum = x[0];for (int i = 1;i<N;i++){if(maxNum < x[i])maxNum = x[i];}int maxDigit = 1;while (maxNum/10){maxDigit++;maxNum /= 10;}return maxDigit;}// 获取一个数number的从右往左第currentDigit位上的数int getCurrentDigit(int number, int currentDigit){int k = 1;while (k!=currentDigit){number/=10;k++;}return number%10;}void radixSort(int x[]) {// 1. 建立一个从0-9的队列数组vector<queue<int*>> vec;for (int i = 0;i<10;i++){queue<int*> q;vec.push_back(q);}int maxDigit = getMaxDigit(x);int currentDigit = 1;while (currentDigit<=maxDigit){// 1. 按每一个数字的currentDigit位进行排序for (int i = 0;i<N;i++){int digit = getCurrentDigit(x[i],currentDigit);auto & q = vec[digit]; // 注意,这里用引用才行!不然不能改变vec里面的queueq.push(&x[i]);}// 2. 把队列捋直了…// 开一个临时的数组,存排序后的数字 --> 一下空间就占了2倍x[]这么大了…int * B = new int [N];int cursor = 0;for (int i = 0;i<10;i++){auto & q = vec[i];while (!q.empty()){auto temp = q.front();B[cursor] = *temp;cursor++;q.pop();}}memcpy(x,B,sizeof(int)*N);showArray(x,N);delete[] B;currentDigit++;}}int main() {int * x = new int[N];int y[] = {27,91,1,97,17,23,84,28,72,5,67,25};for (int i = 0;i<N;i++){x[i] = y[i];}showArray(x,N);radixSort(x);delete []x;system("pause");return 0;}
27 91 1 97 17 23 84 28 72 5 67 25 // 乱序
91 1 72 23 84 5 25 27 97 17 67 28 // 按个位排
1 5 17 23 25 27 28 67 72 84 91 97 // 按十位排

基于纯数组


挺有技巧的。-_-! 看一看也就过了,知道有这么回事儿就行了……
#include <iostream>using namespace std;int maxbit(int data[], int n) //辅助函数,求数据的最大位数{int d = 1; //保存最大的位数int p = 10;for(int i = 0; i < n; ++i){while(data[i] >= p){p *= 10;++d;}}return d;}void radixsort(int data[], int n) //基数排序{int d = maxbit(data, n);int *tmp = new int[n];int *count = new int[10]; //计数器int i, j, k;int radix = 1; // 个位、十位、百位,...for(i = 1; i <= d; i++) //进行d次排序{for(j = 0; j < 10; j++)count[j] = 0; //每次分配前清空计数器// 统计记录数,还是挺有技巧的…for(j = 0; j < n; j++){k = (data[j] / radix) % 10; //统计每个桶中的记录数count[k]++;}// 这是在算累积值for(j = 1; j < 10; j++)count[j] = count[j - 1] + count[j]; //将tmp中的位置依次分配给每个桶// 从后往前收集for(j = n - 1; j >= 0; j--) //将所有桶中记录依次收集到tmp中{k = (data[j] / radix) % 10; // 取出个位,十位,……tmp[count[k] - 1] = data[j];count[k]--;}for(j = 0; j < n; j++) //将临时数组的内容复制到data中data[j] = tmp[j];radix = radix * 10;}delete[]tmp;delete[]count;}int main() {int x[] = {27,91,1,97,17,23,84,28,72,5,67,25};int n = sizeof(x)/sizeof(int);radixsort(x,n);for (int i = 0;i<n;i++){cout<<x[i]<<" ";}cout<<"\n";system("pause");return 0;}



0 0
原创粉丝点击