后缀数组模板(倍增法)

来源:互联网 发布:高仿买家退货淘宝介入 编辑:程序博客网 时间:2024/05/01 07:04
#include<iostream>#include<cstdio>#include<cstring>#include<string>#define maxn 200010using namespace std;char str[maxn];int sa[maxn],wx[maxn],wy[maxn],w[maxn],wv[maxn],Rank[maxn],height[maxn],s[maxn];//sa[i]表示第i大的子串的下标,Rank[i]表示子串下标i的排名,height[i]表示sa[i]与sa[i-1]的最长公共前缀//sa[i]有效范围(i>=1&&i<=n)sa[0]=n,Rank[i]有效范围(i>=0&&i<n)Rank[n]=0,height[i]有效范围(i>=1&&i<=n)height[1]=0int cmp(int *r ,int a ,int b, int j)//比较字符串是否相等{    return (r[a]==r[b])&&(r[a+j]==r[b+j]);}void da(int *r , int n , int m){    int i,j,p,*x=wx,*y=wy,*t;    for(i=0;i<m;i++)//基数排序        w[i]=0;    for(i=0;i<n;i++)        w[x[i]=r[i]]++;    for(i=1;i<m;i++)        w[i]+=w[i-1];    for(i=n-1;i>=0;i--)        sa[--w[x[i]]]=i;    for(j=1,p=0;p<n;j*=2,m=p)//m为基数排序的参数    {        for(p=0,i=n-j;i<n;i++)//第二关键字排序            y[p++]=i;        for(i=0;i<n;i++)            if(sa[i]>=j)            y[p++]=sa[i]-j;        for(i=0;i<n;i++)            wv[i]=x[y[i]];        for(i=0;i<m;i++)//第一第二关键字组合之后的基数排序            w[i]=0;        for(i=0;i<n;i++)            w[wv[i]]++;        for(i=1;i<m;i++)            w[i]+=w[i-1];        for(i=n-1;i>=0;i--)            sa[--w[wv[i]]]=y[i];        for(p=1,i=1,t=x,x=y,y=t,x[sa[0]]=0;i<n;i++)//求出x[]为下一次第一关键字的顺序            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;    }}void calheight(int * r , int n)//求height[]{    int i,k=0,j;    for(i=1;i<=n;i++)    {        if(i==1)          printf("%d",sa[i]+1);        else          printf(" %d",sa[i]+1);        Rank[sa[i]]=i;//Rank和sa相反    }    cout<<endl;    for(i=0;i<n;height[Rank[i++]]=k)        for(k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++);    cout<<height[1];    for(i=2;i<=n;i++)    {        printf(" %d",height[i]);    }    cout<<endl;}int main(){    while(scanf("%s",str)!=EOF)    {        int len=strlen(str);        for(int i=0; i<len; i++)//把字符转化为整形            s[i]=str[i];        s[len]=0;        da(s,len+1,128);//多了一个s[len],长度加1        calheight(s,len);    }    return 0;}



0 0
原创粉丝点击