$tp[i]$ 表示排名为 $i$ 的第二关键字对应的第一关键字的开头.
$rk[i]$ 表示位置 $i$ 的排名.
$sa[i]$ 表示排名为 $i$ 对应的串的位置.
基数排序
void qsort() { for(int i = 0; i <= m ; ++i) C[i] = 0; for(int i = 1; i <= n ; ++i) ++C[rk[i]]; for(int i = 1; i <= m ; ++i) C[i] += C[i - 1]; for(int i = n; i >= 1 ; --i) sa[C[rk[tp[i]]]--] = tp[i]; }
第四个循环比较难懂.
我们已经求得每个第二关键字对应到的第一关键字的位置了.
那就是可能有若干串的第一关键字与第二关键字都对应相同,然而我们的排名系统却并没有把它们算成相同的排名.
#include <bits/stdc++.h> #define maxn 5000000 #define setIO(s) freopen(s".in", "r" , stdin) using namespace std; namespace SA { char str[maxn]; int arr[maxn], C[maxn], rk[maxn], sa[maxn], tp[maxn]; int n, m; void qsort() { for(int i = 0; i <= m ; ++i) C[i] = 0; for(int i = 1; i <= n ; ++i) ++C[rk[i]]; for(int i = 1; i <= m ; ++i) C[i] += C[i - 1]; for(int i = n; i >= 1 ; --i) sa[C[rk[tp[i]]]--] = tp[i]; } void Build() { for(int i = 1; i <= n ; ++i) arr[i] = str[i]; for(int i = 1; i <= n ; ++i) rk[i] = arr[i], tp[i] = i; qsort(); for(int k = 1; k <= n ; k <<= 1) { int p = 0; for(int i = n - k + 1; i <= n ; ++i) tp[++p] = i; for(int i = 1; i <= n ; ++i) if(sa[i] > k) tp[++p] = sa[i] - k; qsort(), swap(rk, tp); rk[sa[1]] = 1, p = 1; for(int i = 2; i <= n ; ++i) { rk[sa[i]] = (tp[sa[i - 1]] == tp[sa[i]] && tp[sa[i - 1] + k] == tp[sa[i] + k]) ? p : ++p; } if(p == n) break; m = p; } } }; int main() { // setIO("input"); scanf("%s",SA::str + 1), SA::n = strlen(SA::str + 1), SA::m = 122, SA :: Build(); for(int i = 1; i <= SA::n ; ++i) printf("%d ",SA::sa[i]); return 0; }