后缀数组
在事先不知道查询的情况下支持多模板匹配。
代码复杂度比后缀树低,且不易写错。
利用倍增的思想,在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; }