1. 程式人生 > >後綴數組

後綴數組

turn tdi swa -a pen aps 消失 spl one

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 using namespace std;
 6 const int MAXN=100001;
 7 
 8 /*  s[]: 文本串
 9    sa[]: 後綴數組,表示“第i名是誰 ”
10       t[]: 即x[], 表示第一關鍵字下“i是第幾名 ”
11      t2[]: 即y[], 表示第二關鍵字下“第i名是誰 ”,對應sa[]
12       c[]: 桶,用來進行基數排序
13 */ 14 15 char s[MAXN]; 16 int sa[MAXN], t[MAXN], t2[MAXN], c[MAXN], n; 17 18 void build_sa(int m) { //構造後綴數組 19 int i, *x=t, *y=t2; //swap函數參數需為指針 20 //基數排序 21 for (i=1; i<m; i++) c[i]=0; //清桶 22 for (i=0; i<n; i++) c[x[i]=s[i]]++; //x[]=s[]:把k=0時的第一關鍵字排名即字符本身賦給x,c[q]++:入桶
23 for (i=1; i<m; i++) c[i]+=c[i-1]; //c[i]~c[i-1]為桶中的數所占的排名,如c[1]=2,c[2]=3執行完該語句變為c[1]=2,c[2]=5表示以1開頭的關鍵字將分配的排名為1,0;以2開頭的分配的排名為4,3,2 24 for (i=n; i>=0; i--) sa[--c[x[i]]]=i;//x[i]"i是第幾名",由於桶的下標按名次來排,所以--c[x[i]]表示分配給i的排名.因為sa表示"第i名是誰",所以sa[i的名次]=i 25 26 for (int k=1; k<=n; k<<=1
) { //倍增 27 int p=0; 28 //用sa[]排序第二關鍵字y[],即把第一關鍵字“抄過來” 29 for (i=n-k; i<n; i++) y[p++]=i; //第二關鍵字的前幾名一定是x中最後k位等於0的,直接賦值 30 for (i=0; i<n; i++) if (sa[i]>=k) y[p++]=sa[i]-k;//把其他排名平移到上一位。因為前K個平移後消失(沒有“上一個關鍵字”所以不被需要),所以不用存;其他的順次平移K位 31 //基數排序第一關鍵字 32 for (i=1; i<m; i++) c[i]=0; 33 for (i=0; i<n; i++) c[x[y[i]]]++; 34 for (i=1; i<m; i++) c[i]+=c[i-1]; 35 for (i=n; i>=0; i--) sa[--c[x[y[i]]]]=y[i]; 36 // 根據sa[]和y[]計算新的x[] 37 swap(x, y); 38 p=1; x[sa[0]]=0; 39 for (i=1; i<n; i++) 40 x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; 41 if (p>=n) break; 42 m=p; 43 } 44 return; 45 }

(無註釋版)

技術分享
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int MAXN=100001;

char s[MAXN];  
int sa[MAXN], t[MAXN], t2[MAXN], c[MAXN], n;

void build_sa(int m) {        
    int i, *x=t, *y=t2;         
    
    for (i=1; i<m; i++) c[i]=0;           
    for (i=0; i<n; i++) c[x[i]=s[i]]++; 
    for (i=1; i<m; i++) c[i]+=c[i-1];    
    for (i=n; i>=0; i--) sa[--c[x[i]]]=i;
    
    for (int k=1; k<=n; k<<=1) {        
        int p=0;
        for (i=n-k; i<n; i++) y[p++]=i;    
        for (i=0; i<n; i++) if (sa[i]>=k) y[p++]=sa[i]-k;
         
        for (i=1; i<m; i++) c[i]=0;
        for (i=0; i<n; i++) c[x[y[i]]]++;
        for (i=1; i<m; i++) c[i]+=c[i-1];
        for (i=n; i>=0; i--) sa[--c[x[y[i]]]]=y[i];
      
         swap(x, y);
        p=1; x[sa[0]]=0;
        for (i=1; i<n; i++)
            x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
        if (p>=n) break;
        m=p;
    }
    return;
}
View Code

後綴數組