后缀数组详解
这是一部分,以后还会更新的
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #define maxn 10000 using namespace std; char s[maxn],s1[maxn]; int sa[maxn];/***sa[第几大]=第几位开始的后缀***/ int Rank[maxn];/***rank[第几位开始的后缀]=第几大***/ int t[maxn],t2[maxn],c[maxn],n; void build_sa(int m) { int i,*x=t,*y=t2; //基数排序 for(i=0;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-1;i>=0;--i)sa[--c[x[i]]]=i; for(int k=1;k<=n;k<<=1) { int p=0; /**直接利用sa数组排序第二关键字**/ 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=0;i<m;++i)c[i]=0; for(i=0;i<n;++i)c[x[y[i]]]++; for(i=0;i<m;++i)c[i]+=c[i-1]; for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; /**根据sa和y数组计算新的x数组**/ 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;/**以后即使继续倍增,sa也不会改变,退出**/ m=p;/**下次基数排序的最大值**/ } } int m; int cmp_suffix(char *pattern,int p) { return strncmp(pattern,s+sa[p],m); /*************************** 用 法: int strncmp(char *str1, char *str2, int maxlen); 说明:此函数功能即比较字符串str1和str2的前maxlen个字符。 如果前maxlen字节完全相等,返回值就=0; 在前maxlen字节比较过程中,如果出现str1[n]与str2[n]不等, 则返回(str1[n]-str2[n])。 ****************************/ } int find(char *p) { m=strlen(p); if(cmp_suffix(p,0)<0)return -1;/**下界为第0个后缀**/ if(cmp_suffix(p,n-1)>0)return -1;/**上界为第n-1个后缀**/ int l=0,r=n-1; while(r>=l)/**二分判断是否有该后缀与P的公共前缀=p的长度**/ { int m=l+(r-l)/2; int res=cmp_suffix(p,m); if(!res)return m; if(res<0)r=m-1;else l=m+1; } return -1; } int main() { scanf("%s",s); n=strlen(s); build_sa(300);/**char的最大字符值**/ scanf("%s",s1); cout<<find(s1);/**从s中查找s1**/ return 0; }
下面这个是基础版,常数会大些,复杂度不变
1 #include <iostream> 2 #include <string> 3 #include <cstring> 4 #include <algorithm> 5 #include <cstdio> 6 #define maxlen 1000 7 #define maxn 10000 8 9 using namespace std; 10 11 char s[maxlen],s1[maxlen]; 12 int sa[maxn],tsa[maxn],Rank[maxn],trank[maxn],sum[maxn]; 13 int n,m; 14 15 void sorting(int j) 16 { 17 memset(sum,0,sizeof(sum)); 18 for(int i=1;i<=n;i++)sum[Rank[i+j]]++; 19 for(int i=1;i<=maxlen;i++)sum[i]+=sum[i-1]; 20 for(int i=n;i!=0;i--)tsa[sum[Rank[i+j]]--]=i; 21 22 memset(sum,0,sizeof(sum)); 23 for(int i=1;i<=n;++i)sum[Rank[i]]++; 24 for(int i=1;i<=maxlen;++i)sum[i]+=sum[i-1]; 25 for(int i=n;i!=0;i--)sa[sum[Rank[tsa[i]]]--]=tsa[i]; 26 } 27 28 void build_sa() 29 { 30 int p; 31 for(int i=0;i!=n;++i)trank[i+1]=s[i]; 32 for(int i=1;i<=n;++i)sum[trank[i]]++; 33 for(int i=1;i<=maxlen;++i)sum[i]+=sum[i-1]; 34 for(int i=n;i!=0;i--)sa[sum[trank[i]]--]=i; 35 Rank[sa[1]]=1; 36 for(int i=2,p=1;i<=n;++i) 37 { 38 if(trank[sa[i]]!=trank[sa[i-1]])p++; 39 Rank[sa[i]]=p; 40 } 41 for(int j=1;j<=n;j*=2) 42 { 43 sorting(j); 44 trank[sa[1]]=1;p=1; 45 for(int i=2;i<=n;++i) 46 { 47 if((Rank[sa[i]]!=Rank[sa[i-1]]) || (Rank[sa[i]+j]!=Rank[sa[i-1]+j]))p++; 48 trank[sa[i]]=p; 49 } 50 for(int i=1;i<=n;++i)Rank[i]=trank[i]; 51 } 52 } 53 54 void init() 55 { 56 memset(sum,0,sizeof(sum)); 57 memset(Rank,0,sizeof(Rank)); 58 memset(trank,0,sizeof(trank)); 59 memset(sa,0,sizeof(sa)); 60 memset(tsa,0,sizeof(tsa)); 61 } 62 63 int cmp_suffix(char *pattern,int p){return strncmp(pattern,s+sa[p]-1,m);} 64 65 int finds(char *p) 66 { 67 m=strlen(p); 68 if(cmp_suffix(p,1)<0)return -1; 69 if(cmp_suffix(p,n)>0)return -1; 70 int l=1,r=n; 71 while(r>=l) 72 { 73 int m=l+(r-l)/2; 74 int res=cmp_suffix(p,m); 75 if(!res)return m; 76 if(res<0)r=m-1;else l=m+1; 77 } 78 return -1; 79 } 80 81 int main() 82 { 83 init(); 84 scanf("%s",s); 85 n=strlen(s); 86 build_sa(); 87 scanf("%s",s1); 88 cout<<finds(s1); 89 return 0; 90 }