【算法】基数排序

算法-基数排序


前置知识

思路

都将基数排序视为最快的排序算法(对整数而言)。
这是一个很鬼畜的算法,请做好心理准备。。。

我们现在有一个序列,怎么对它排序?
这是一个非常经典的问题,这里我们使用一个经典的基础算法——基数排序解决。
为了体现基数排序的方式,我们使用多位数。
这里有一个多位数序列,要对其升序排序。
654 784 137 914 261 359 \begin{array}{cc} 654&784&137&914&261&359 \end{array} 654784137914261359
我们从个位开始考虑,因为越往后的考虑更有决定性,所以从低位向高位考虑
首先按照个位排序。
261 654 784 914 137 359 \begin{array}{cc} 261&654&784&914&137&359 \end{array} 261654784914137359
再按十位排序,但是需要保证排序具有稳定性,即该位相同时必须以元素原来在数组中的顺序排序
914 137 654 359 261 784 \begin{array}{cc} 914&137&654&359&261&784 \end{array} 914137654359261784
最后按百位排序
137 261 359 654 784 914 \begin{array}{cc} 137&261&359&654&784&914 \end{array} 137261359654784914
排序完成。
那么借助计数排序的思想,我们利用数组来处理每一位。
例如将下面的序列按十位升序。
621 391 722 194 337 118 \begin{array}{cc} 621&391&722&194&337&118 \end{array} 621391722194337118
我们进行计数。
0 1 2 3 4 5 6 7 8 9 0 1 2 1 0 0 0 0 0 2 \begin{array}{cc} 0&1&2&3&4&5&6&7&8&9\\ \gray0&1&2&1&\gray0&\gray0&\gray0&\gray0&\gray0&2 \end{array} 00112231405060708092
对计数数组做前缀和
0 1 2 3 4 5 6 7 8 9 0 1 3 4 4 4 4 4 4 6 \begin{array}{cc} 0&1&2&3&4&5&6&7&8&9\\ 0&1&3&4&4&4&4&4&4&6 \end{array} 00112334445464748496
不难发现, i i i 个元素实际上为十位为 i i i 的最后一个元素排序后的位置,故从后向前遍历原数组,每次放在第 i i i 个元素标出的位置,并将该元素减 1 1 1
故排序后得到:
118 621 722 337 391 194 \begin{array}{cc} 118&621&722&337&391&194 \end{array} 118621722337391194
复制会原数组,完成。


一些卡常小技巧

基数排序不够快怎么办?凉拌炒鸡蛋,好吃又好看
下面为对几个 int \text{int} int 数组排序的方法。

  • std::sort()
  • 2 16 2^{16} 216 跑两趟
  • 2 11 2^{11} 211 跑三趟
  • 2 8 2^8 28 跑四趟
  • 10 10 10 跑十趟

CCF 评测机的 L1 缓存大小约为 2 13 2^{13} 213 int \text{int} int,所以建议 2 11 2^{11} 211 跑三趟。
但是我更喜欢写 2 8 2^8 28


实现代码
  • S = 2 8 S=2^8 S=28 版本(我更喜欢写这个
void CountSort(int a[],int c[],int n,int w){
	const int S=1<<8;
	static int b[S];
	for (int i=0;i<S;i++) b[i]=0;
	for (int i=1;i<=n;i++) b[a[i]>>w&(S-1)]++;
	for (int i=1;i<S;i++) b[i]+=b[i-1];
	for (int i=n;i;i--) c[b[(a[i]>>w)&(S-1)]--]=a[i];
}
int tmp[MAXN];
void RadixSort(int a[],int n){
	CountSort(a,tmp,n,0);
	CountSort(a,tmp,n,8);
	CountSort(a,tmp,n,16);
	CountSort(a,tmp,n,24);
}

练习
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值