后缀数组 (由倍增算法构造)

来源:互联网 发布:淘宝产品卖点怎么写 编辑:程序博客网 时间:2024/05/01 09:55
//倍增算法构造后缀数组//时间复杂度O(nlogn)空间复杂度O(n)#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define MAXN 110000int n;//n为处理字符串s的长度char s[MAXN],tmp[MAXN];//s为输入的字符串int sa[MAXN],t[MAXN],t2[MAXN],c[MAXN];int idx(char c){return c-'a';}void print(int *num,int d){printf("\n");for(int i=0;i<d;i++)printf("%d %d\n",i,num[i]);printf("\n");}//构造字符串s的后缀数组,每个字符值必须为0--m-1void 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]=idx(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)//判断模版s是否为后缀p的前缀{return strncmp(pattern,s+sa[p],m);}//多模版匹配问题。直接在后缀数组里进行二分查找,找到其中一个匹配位置(可以改成找出所有位置的代码)//每次查询的时间复杂度为O(mlogn),其中n为文本串的长度,m为模式串的长度/*int find(char *p){m=strlen(p);if(cmp_suffix(p,0)<0)return -1;if(cmp_suffix(p,n-1)>0) return -1;int L=0,R=n-1;while(L<=R)//二分查找{int M=L+(R-L)/2;int res=cmp_suffix(p,M);if(!res)return M;if(res<0)R=M-1;elseL=M+1;}return -1;//找不到}*///输出所有位置的find函数int find(char *p){m=strlen(p);if(cmp_suffix(p,0)<0)return -1;if(cmp_suffix(p,n-1)>0) return -1;int L=0,R=n-1;while(L<=R)//二分查找{int M=L+(R-L)/2;int res=cmp_suffix(p,M);if(!res){printf("%d\n",sa[M]);for(int i=M-1;i>=0;i--)if(cmp_suffix(p,i)==0){printf("%d\n",sa[i]);}elsebreak;for(int i=M+1;i<n;i++)if(cmp_suffix(p,i)==0){printf("%d\n",sa[i]);}elsebreak;return M;}if(res<0)R=M-1;elseL=M+1;}return -1;//找不到}int main(){int i,t,x;freopen("e:\\in.txt","r",stdin);while(scanf("%s",s)==1){n=strlen(s);build_sa(26);printf("\nsa:");print(sa,n);scanf("%d",&t);for(i=1;i<=t;i++){scanf("%s",tmp);x=find(tmp);if(x==-1)printf("%d\n",x);}}return 0;}

原创粉丝点击