浅谈后缀数组(对模板的理解

显然可知对于后缀数组最难理解的就是sa数组和rank数组的构建,而sa与rank数组之间有一个相互转化关系,这就必须理解sa数组和rank数组的含义,sa数组代表的是排名为i的后缀第一个字符所在的位置,而rank数组则表示的是第i个位置的后缀的排名;通过这个关系,我们可以实现sa与rank之间的转化,所以整个关键就成了如何去求他们其中的一个,根据,我的学习笔记来源这几个大神的博客可做参考:

                                                                                     1,http://blog.csdn.net/jokes000/article/details/7839686;

                                                                                       2,http://www.cnblogs.com/shanchuan04/p/5324009.html;前者具有深刻的代码分析及应用,后者更为形象的理解后缀数组;

下面之间贴上我自己对于后缀数组的理解:

 

#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<map>
#include<cstdio>
#include<cstring>
#define MAXN 100005
using namespace std;
char a[MAXN];
int rank[MAXN];int td[MAXN];int sa[MAXN];int Rank[MAXN];int txt[MAXN];int t1[MAXN];int t2[MAXN];
int height[MAXN];int h[MAXN];
bool cmp(int t[],int e,int w,int f){
	return t[e]==t[w]&&t[e+f]==t[w+f];
}
void Sa(char a[]){
	int *rank=t1;int *td=t2;
	int m=26;
	int len=strlen(a);
	for(int i=0;i<m;i++) txt[i]=0;
	for(int i=0;i<len;i++){
		rank[i]=a[i]-'a';
		txt[a[i]-'a']++;
	}
	for(int i=1;i<m;i++) txt[i]+=txt[i-1];
	for(int i=len-1;i>=0;i--) sa[--(txt[a[i]-'a'])]=i;
//运用基数排序(计数排序)对于sa数组进行初始化sa;
	for(int k=1;k<=len;k*=2){
		int p;
		p=0;
		for(int i=len-k;i<len;i++) td[p++]=i;
		for(int i=0;i<len;i++){
			if(sa[i]>=k) td[p++]=sa[i]-k;
		}
//td数组表示的是第二关键字排名,详情见第二链接;
		for(int i=0;i<m;i++)  txt[i]=0;
		for(int i=0;i<len;i++) txt[rank[td[i]]]++;
		for(int i=1;i<m;i++) txt[i]+=txt[i-1];
		for(int i=len-1;i>=0;i--) sa[--txt[rank[td[i]]]]=td[i];
//依照第一关键词的排序,复合第二关键词的顺序,进行排序更新sa数组;
//更新完sa数组后  就对rank数组进行更新,因为rank数组可能存在字符串相等的情况 即rank数组下不同的i可能对应相同的值所以必须对其离散化  也就是判断是否会存在相同的字符串
//运用第一关键词和第二关键词的二元组来进行离散
		swap(rank,td);
		rank[sa[0]]=0;
		p=0;
		for(int i=1;i<len;i++)  rank[sa[i]]=cmp(td,sa[i-1],sa[i],k)?p:++p;
		if(p==len)  return ;
	}
	return ;
}
void pd(char a[]){
	int len=strlen(a);
	for(int i=0;i<len;i++)  Rank[sa[i]]=i;
}
void hh(char a[]){
	int len=strlen(a);
	h[sa[0]]=0;
	height[0]=0;
	for(int i=0;i<len;i++){
		int xx=Rank[i];
		int yy=sa[Rank[i]-1];
		int flag=0;
		if(Rank[i]==0)  continue;
	    int p=h[i-1]-1;
	    int w=i;
	    if(p<0){
	    	p=0;
		}
		else{
			w+=p;yy+=p;
		}
	 	while(a[w]!='\0'&&a[yy]!='\0'){
	 		if(a[w]==a[yy])  p++;
	 		else{
	 			break;
			 }
			 w++;yy++;
		 }
	 h[i]=p;
	 height[Rank[i]]=h[i];
}
//hh函数是求height数组 即在排序后后缀的与前一个后缀的公共前缀的字符数
//关键运用对于i满足,h[i]>=h[i-1]-1;具体证明可以百度
return ;
}
int main(){
	scanf("%s",a);
	Sa(a);
	for(int i=0;i<strlen(a);i++) cout<<sa[i]<<" ";
	cout<<endl;
	cout<<"Rank:"<<endl;
	pd(a);
	for(int i=0;i<strlen(a);i++) cout<<Rank[i]+1<<" ";
	cout<<endl;
	cout<<"Height:"<<endl;
	hh(a);
	for(int i=0;i<strlen(a);i++)  cout<<height[i]<<" ";
	cout<<endl;
}

这算是这几天来的理解吧  在AC了一道模板题后  决定写下来这些心得 大致思路分析就是这样的还是需要多多刷题来巩固这些模板和思维

 

                                ---- 眼界的宽度决定以后的成就

 

posted @ 2017-10-03 20:25  wang9897  阅读(115)  评论(0编辑  收藏  举报