【基數排序】基數排序


Algorithm

Task

給定 \(n\) 個整數,請排序后輸出

Limitations

要求時間復雜度 \(O((n + T)\log_TA)\),空間復雜度 \(O(T)\) ,其中 \(T = 32768\)\(A\) 是序列中最大元素的值

Solution

前兩天小學妹問我基數排序怎么寫,然后我就想起來以前給 ddosvoid 大爺口胡過一個排序,大爺聽完說這就是基排,於是就講給了小學妹(霧),但是我並不確定這是不是基排(((,總之復雜度一致就完事了

考慮桶排序,將所有數字壓入桶中,正向掃描整個桶即可。但是當 \(A\) 過大時,空間無法承受。

考慮這樣一個事實:對於兩個數字 \(A,~B\),將他們二進制分成兩段,先比較前半段,如果大小不同,那么前半段的大小關系即為 \(A,~B\) 的大小關系,否則比較后半段,二進制后半段較大的一定更大。

我們發現這個結論可以拓展到將數字分成任意段,於是我們考慮將二進制每 \(log_2T\) 位分一段,對每段做桶排序,然后合並結果即可。

那么出現了一個問題:如果從前向后進行比較的話,需要對前面二進制相同的每組數字分別桶排序,這樣最多會做 \(O(n)\) 次桶排序,每次 \(O(T)\),總復雜度 \(O(nT)\),當場去世。

但是考慮一個事實:桶排序是穩定的排序,即如果在某次排序中 \(A\) 先於 \(B\) 被掃描到,且本次排序認為 \(A = B\),則掃描桶的時候 \(A\) 也會先於 \(B\) 被掃描。於是我們可以從后往前比較每段,在每次排序前,我們保證已經排過的段的部分的大小關系,在排序結束后,按照新的大小關系從桶中取出。由於之前排過的段的大小已經確定,且桶排序是穩定的,所以這次排序以后已排段的大小關系還是正確的。數學歸納可以證明這樣排序的正確性。

考慮復雜度:一共進行了 \(O(\log_TA)\) 次排序,每次 \(O(n + T)\) 進行桶排,於是總時間復雜度 \(O((n + T) \log_TA)\);空間上,桶排只需要需要 \(O(T)\) 的空間。

事實上,如果數據中有負數,只需要正負分開,分別做一遍即可。

Sample

【P1177】【模板】快速排序

Description

\(n\) 個值域為 \([1, 10^9]\) 的整數,要求排序后輸出

Limitaions

\(n \leq 10^5\)

Solution

板板題

Code

#include <cstdio>
#include <vector>

const int t = 15;
const int d = 32767;
const int maxn = 100005;
const int maxt = 32768;

struct M {
  int pre, pro;
  
  M (const int x = 0) : pre(x >> t), pro(x & d) {}
};
M MU[maxn];

int n;
int ans[maxn];
std::vector<int>bk[maxt];

void Radix_Sort();

int main() {
  freopen("1.in", "r", stdin);
  qr(n);
  for (int i = 1, x; i <= n; ++i) {
    x = 0; qr(x); MU[i] = M(x);
    ans[i] = i;
  }
  Radix_Sort();
  for (int i = 1; i <= n; ++i) {
    qw((MU[ans[i]].pre << t) | MU[ans[i]].pro, i == n ? '\n' : ' ', true);
  }
  return 0;
}

void Radix_Sort() {
  for (int i = 1; i <= n; ++i) {
    bk[MU[ans[i]].pro].push_back(ans[i]);
  }
  int cnt = 0;
  for (auto &i : bk) {
    for (auto u : i) {
      ans[++cnt] = u;
    }
    i.clear();
  }
  for (int i = 1; i <= n; ++i) {
    bk[MU[ans[i]].pre].push_back(ans[i]);
  }
  cnt = 0;
  for (auto &i : bk) {
    for (auto u : i) {
      ans[++cnt] = u;
    }
  }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM