行路难,行路难,多歧路,今安在?长风破浪会|

hhhqx

园龄:1年8个月粉丝:9关注:14

O(n) 排序 - 基数排序

O(n) 排序 —— 基数排序

基数排序

来举个例子:

  • 我们需要对 c1 4 5 2 3 1 3 进行排序
  • 定义 a 2 3 5 6 7,第 i 个表示序列中有 ai 个小于 i 的元素。
  • 从左向右扫一遍,序列的确定部分如下
    • 加入 1? 1 ? ? ? ? ?a 变为1 3 5 6 7
    • 加入 4? 1 ? ? ? 4 ?a 变为1 3 5 5 7
    • 加入 5? 1 ? ? ? 4 5a 变为1 3 5 5 6
    • 加入 2? 1 2 ? ? 4 5a 变为1 2 5 5 6
    • 加入 3? 1 2 ? 3 4 5a 变为1 2 4 5 6
    • 加入 11 1 2 ? 3 4 5a 变为0 2 4 5 6
    • 加入 31 1 2 3 3 4 5a 变为0 2 3 5 6

相信你看完例子就已经懂了基数排序。

进阶基数排序

我们注意到基数排序可以是稳定排序,且时间复杂度是 O(n+maxi1nci)

不带 log 看起来就很

但是这个 maxi1nci 就很烦。

于是!我们想到将 ci 分成两半,变为两个关键字排序。

这样还可以基数排序吗?当然可以!

因为基数排序可以是稳定的,所以对第二关键字排一遍,接着对第一关键字排一遍。

代码实现起来有一些小小的细节需要注意!

#include <bits/stdc++.h>

using namespace std;
using LL = long long;
using PII = pair<int, int>;

const int MAXN = 1e5 + 3, MAXW = 1e5 + 3;

int n;
int r[MAXW];
PII a[MAXN], b[MAXN];

int main(){
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n;
  for(int i = 1, w; i <= n; i++){
    cin >> w, a[i] = {w / 100000, w % 100000};
  }
  for(int i = 1; i <= n; i++) r[a[i].second]++;
  for(int i = 0; i <= 1e5; i++) r[i] += r[i - 1];
  for(int i = n; i >= 1; i--) b[r[a[i].second]] = a[i], r[a[i].second]--;
  for(int i = 0; i <= 1e5; i++) r[i] = 0; // 清空
  for(int i = 1; i <= n; i++) r[b[i].first]++;
  for(int i = 1; i <= 1e5; i++) r[i] += r[i - 1];
  for(int i = n; i >= 1; i--) a[r[b[i].first]] = b[i], r[b[i].first]--;
  for(int i = 1; i <= n; i++){
    cout << a[i].first * 100000 + a[i].second << " ";
  }
  return 0;
}

本文作者:hhhqx

本文链接:https://www.cnblogs.com/huangqixuan/p/17993505

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   hhhqx  阅读(36)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起