zoukankan      html  css  js  c++  java
  • 浅谈后缀数组(对模板的理解

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

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

  • 相关阅读:
    【LoadRunner-Vuser Generator】录制脚本设置Recording Options
    【LoadRunner-内部结构】
    【LoadRunner-工作过程】
    单片机上内存管理(重定义malloc free)的实现
    stm32模块的初始化顺序要求的更改设值
    [CAN波形分析] 一次CAN波形分析之旅
    w5500调试小记
    keil mdk中save和load指令,在调试中比较有用,以及hex格式的学习
    PHP启用session后抛 session_start(): open(/var/lib/php/session/sess_... 的解决办法
    brew 方式安装的php,关闭与重启----mac启动,关闭php-fpm方式
  • 原文地址:https://www.cnblogs.com/wang9897/p/7624384.html
Copyright © 2011-2022 走看看