后缀数组详解

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

#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 }
原文地址:https://www.cnblogs.com/mrxsc/p/2935658.html