后缀数组


在事先不知道查询的情况下支持多模板匹配。
代码复杂度比后缀树低,且不易写错。

  利用倍增的思想,在O(N log N)的时间内构造出来。

  这里不提供思路,只提供代码的讲解。

  讲解在代码的注释里。

 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

 

posted @ 2017-06-12 07:30  3918张佳  阅读(146)  评论(0编辑  收藏  举报