山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

[总结]后缀数组: 注释+模板

  

 

以下模板单单注释了如何使用,算法详解可参考 罗穗骞《后缀数组——处理字符串的有力工具》

 

算法注释:

#include<cstdio>
#include<cstring>
#include<iostream>
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std;
 
const int maxn = 
 
 
int s[maxn];
int sa[maxn],c[maxn],t[maxn],t2[maxn];
 
void build_sa(int m,int n) {
    int i,*x=t,*y=t2; 
    //提前一次基数排序 将sa[]求出
	//基数排序后满足x递增 当x相同时 按照i递增的顺序 
    //sa[i]在每次k循环完之后都保留着目前排名第i的是谁 
	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) {
    	//排序第二关键字 
    	//根据已经算出的sa[]算出y[]
		//y[i]中保存着谁的第二关键字排名第i (i的第二关键字为i+k) 
        int p=0;
        for(i=n-k;i<n;i++) y[p++]=i;						//第二关键字为0的排在前面 
        for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;		//根据sa求出y 
        //排序第一关键字 
        //基数排序后满足x递增 当x相同时 按照y递增的顺序 
        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];
        //交换xy 并计算下一轮的x
		//此时y中保存着原来的x  新的x是由排序产生的排名
        swap(x,y);
        p=1; x[sa[0]]=0;
        for(i=1;i<n;i++)
            x[sa[i]]=y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;	
		//若二元组的第一关键字与第二关键字相同的则名次相同
        if(p>=n) break;		//全部有序 即没有两个的名次是相等的 则停止倍增 
        m=p;	//m<-总名次数 
    }
}

int rank[maxn],height[maxn];
void getHeight(int n) {
	//H[i]=height[rank[i]]
	//H[i]>=H[i-1]-1
    int i,j,k=0;
    for(i=0;i<=n;i++) rank[sa[i]]=i;
    for(i=0;i<n;i++) {
        if(k) k--;
        j=sa[rank[i]-1];
        while(s[j+k]==s[i+k]) k++;
        height[rank[i]]=k;
    }
}

  

 

 使用注释:

#include<cstdio>
#include<cstring>
#include<iostream>
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std;

const int maxn =             //长度范围 


int s[maxn];                //字符串对应Ascii码 使用前可提前构造 
int sa[maxn],c[maxn],t[maxn],t2[maxn];

//m代表字符最大值 n代表字符串长
//常常需要在字符串末尾加0以防止RE 令s[n]=0 调用build_sa(m,n+1)即可 
void build_sa(int m,int n) {
    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;
        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];
        
        swap(x,y);
        p=1; x[sa[0]]=0;
        for(i=1;i<n;i++) 
            x[sa[i]]=y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
        if(p>=n) break;
        m=p;
    }
}
//n代表字符串长度
//调用getHeight(n)即可 
int rank[maxn],height[maxn];
void getHeight(int n) {
    int i,j,k=0;
    for(i=0;i<=n;i++) rank[sa[i]]=i;  //[0,n]
    for(i=0;i<n;i++) {                  //不计算height[n] 即末尾0 
        if(k) k--;
        j=sa[rank[i]-1];
        while(s[j+k]==s[i+k]) k++;
        height[rank[i]]=k;
    }
}

 

posted on 2015-11-28 18:35  hahalidaxin  阅读(225)  评论(0编辑  收藏  举报