后缀数组 魔板
為什么一開始要再字符串末尾多算個0呢
因為當開始分關鍵字比較的時候 最后要組成兩個
字符所以要多個0 什么你有問我為什么填0
因為0小啊 先處理唄
雖然
sa是根據每個字符確定的大小
也就是排布的每個字符的排名
但是在初次求第二關鍵字排序的時候
可以使用sa的結論
首先吧sa后面的0排到最前面
那么0的數量 也就是從n-j到n開區間 都是0作為第二關鍵字的區域
也就是這句話
這一句
for(int i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;是表示
當0已經排完了
現在再把非0的排進去
如何排進去呢?
我們看
我們從1-n開區間枚舉
如果sai大于等于j說明排到第i位的后綴的位置是大于等于j,大于等于
現在的枚舉長度的
那么就把他們放到y
也就是第二關鍵字排名數組中 并將其值記錄為本字符串的開始位置sa[i]-j;
由于y數組中是按照第二關鍵字排序后存放的開始位置的數組
那么當我按照y從x數組中把值提取出來付給wv數組時 就相當于
把要比較的長度為2的倍增一倍的數組放到wv中去了
接下來就用下面的四個for循環來按第一關鍵字對合并后的字符串進行排序,最后更新sa道理同上面對字符串第一個字符進行排序的四個for循環。
1:盛放j=1 長度為2 由于是按照低位排過序后的數組放入的wv 而wv存放的是第一關鍵字的值 為后續排序做準備
2:按照第一關鍵字的順序將其裝桶標記
3:按照第一關鍵字的順序計算前綴和
4: 對于每個wv 是先按照第二關鍵字排序順序裝入的ws 也就是基數排序的本質
此時在2句又按照第一關鍵字的值(存儲的是第一關鍵字的值)排好了序
每次– 逆序處理
此時得到的sa數組 就是一個在以第一二關鍵字合并的情況下按照其大小按照加上第一關鍵字的新順序從高到低
講y數組(記錄的是初始位置)的值付給sa
表示字符串排序第i個位于y[i]
最后再來看下cmp函數的作用
如果y也就是原來的x數組下a位置的和b位置的相等 并且第二關鍵字也相等
那么就會返回1
返回1就會讓這段字符的實質排名為p-1 返回0表示不相等那么就說明兩段不相等
讓其等于p 則兩段字符的排名相同
最終的p值 就代表我一共有排到了幾 其中有可能有排名相等的項
那么這個p也就是其中下一循環的m值 也就是下一次循環
其中每個單關鍵字的排名不會超過m 存儲到x數組中
魔板:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> using namespace std; typedef long long ll; int n,m; int *t,sa[1010],a[1010],b[1010],ms[1010],mv[1010]; char aa[50]; void LSD(int n,int *x,int *y,int *Ws,int *wv){m = 130;for(int i=0;i<m;i++)Ws[i]=0;for(int i=0;i<n;i++)Ws[x[i]=aa[i]]++;for(int i=1;i<m;i++)Ws[i]+=Ws[i-1];for(int i=n-1;i>=0;i--)sa[--Ws[x[i]]]=i;for(int p=1,m,j=1;p<n;j<<=1,m=p){p=0;for(int i=n-j;i<n;i++)y[p++]=i;for(int i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;for(int i=0;i<n;i++)wv[i]=x[y[i]];for(int i=0;i<m;i++)Ws[i]=0;for(int i=0;i<n;i++)Ws[wv[i]]++;for(int i=1;i<m;i++)Ws[i]+=Ws[i-1];for(int i=n-1;i>=0;i--)sa[--Ws[wv[i]]]=y[i];int i;for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)x[sa[i]] =(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]) ?p-1:p++;}return; } int main() {scanf("%s",aa);LSD(strlen(aa)+1,a,b,ms,mv);for(int i=0;i<strlen(aa);i++)printf("%d ",sa[i]);puts("");return 0; }總結
- 上一篇: 单点登录系统cas资料汇总
- 下一篇: autocad不能画图_学了这些CAD技