基础算法:基数排序

说到排序大家会想到什么呢

O ( N 2 ) O(N^2) 的选择冒泡排序

还是 O ( N l o g N ) O(NlogN) 的快排,归并排序等等

还是 O ( N 1.5 ) O(N^{1.5}) 的希尔排序虽然我不会

还是对空间要求大的 O ( N ) O(N) 的桶排?

如果想“快速”的对一个数列进行排序,最快的肯定是桶排,但是如果 m a x ( a i ) 1 0 8 max(a_i)\geq10^8 那桶排他就死了

这里给大家介绍一种高级的 O ( N ) O(N) 的排序算法——基数排序

当然你也不要高兴的太早,基数排序名义上是 O ( N ) O(N)

但是他的常数非常的大,详细写大概是这个样子的: O ( n l o g ( r ) m ) O(nlog(r)m) ,其中r表示 l o g 10 m a x ( a [ i ] ) + 1 {log_{10}}^{max(a[i])}+1 ,m表示容器个数,也就是10,等会下文会讲到

所以其实我们看到基数排序是最后时间复杂度和快排的 O ( N l o g N ) O(NlogN) 也差不多

下面来讲这个算法

首先比较这列数的个位,把个位相同的放到一个桶里(像桶排一样)

然后把他们按照现在正在排的那一位从小到大(或从大到小),倒出来

一直重复执行 l o g 10 m a x ( a [ i ] ) + 1 {log_{10}}^{max(a[i])}+1 (上文提到的r)遍

最后得到的就是最终要的序列。

我们用图来解释一下

比如我们要排一列数

20,6,5,505,9,1,17,7,91

那么我们要排三次序

第一次排序

b o x i box_i 桶内数
0 20
1 1,91
2 N U L L NULL
3 N U L L NULL
4 N U L L NULL
5 5,505
6 6
7 17,7
8 N U L L NULL
9 9

然后我们按顺序取出

得到20,1,91,5,505,6,17,7,9

第二次排序

b o x i box_i 桶内数
0 1,5,505,6,7,9
1 17
2 20
3 N U L L NULL
4 N U L L NULL
5 N U L L NULL
6 N U L L NULL
7 N U L L NULL
8 N U L L NULL
9 91

再按顺序取出,得到1,5,505,6,7,9,17,20,91

第三次排序

b o x i box_i 桶内数
0 1,5,6,7,9,17,20,91
1 N U L L NULL
2 N U L L NULL
3 N U L L NULL
4 N U L L NULL
5 505
6 N U L L NULL
7 N U L L NULL
8 N U L L NULL
9 N U L L NULL

再取出,得到1,5,6,7,9,17,20,91,505——大功告成

上代码:

# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <stack>
# include <ctime>
using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define mct(a,b) memset(a,b,sizeof(a))
# define gc getchar()
typedef long long ll;
const int N=1e5+5;
const int inf=0x7fffffff;
const double eps=1e-7;
template <typename T> void read(T &x){
	x=0;int f=1;
	char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
	x*=f;
}

int n,a[N];
int cnt[N],pour[N];

inline int getd(){
	int d=1;
	int p=10;
	Rep(i,1,n){
		while(a[i]>=p){
			p*=10;
			d++;
		}
	}
	return d;
}

inline void radixsort(){
	int d=getd();
	int radix=1;
	Rep(i,1,d){
		memset(cnt,0,sizeof(cnt));
		Rep(j,1,n){
			int k=(a[j]/radix)%10;
			cnt[k]++;
		}
		Rep(j,1,9)cnt[j]+=cnt[j-1];
		_Rep(j,n,1){
			int k=(a[j]/radix)%10;
			pour[cnt[k]]=a[j];
			cnt[k]--;
		}
		memcpy(a,pour,sizeof(pour));
		radix*=10;
	}
}

int main()
{
	read(n);
	Rep(i,1,n)read(a[i]);
	radixsort();
	Rep(i,1,n)printf("%d ",a[i]);
	puts("");
	return 0;
}

听说基数排序有一种位运算优化可以真正优化到 O ( N ) O(N)

但是我也不会

发布了18 篇原创文章 · 获赞 3 · 访问量 1262

猜你喜欢

转载自blog.csdn.net/devout_/article/details/100101756