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

来源:互联网 发布:php workerman swoole 编辑:程序博客网 时间:2024/05/20 05:28

显然可知对于后缀数组最难理解的就是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 100005using 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了一道模板题后  决定写下来这些心得 大致思路分析就是这样的还是需要多多刷题来巩固这些模板和思维

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

原创粉丝点击