zoukankan      html  css  js  c++  java
  • 后缀数组详解

    这是一部分,以后还会更新的

    #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 }
  • 相关阅读:
    git 强制覆盖本地
    .gitignore 配置
    Git fetch和git pull的区别
    时间函数 date strtotime
    page show
    prepare PDO
    Lucene搜索方法总结
    lucene索引日期和数字
    lucene 3.0.2 + 多文件夹微博数据(时间,微博)构建索引
    lucene 使用注意
  • 原文地址:https://www.cnblogs.com/mrxsc/p/2935658.html
Copyright © 2011-2022 走看看