后缀数组

刚学了后缀数组,似懂非懂,看了很久的代码,也理解了很久,总结出了一份自己的代码


包含满满的注释:


#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<cmath>
using namespace std;
const int maxn=100+5;
int n;
char s[maxn];
int rank[maxn],sa[maxn],height[maxn];
int wd[maxn],wa[maxn],wb[maxn];
//wd辅助基数排序  每次技术使用 
//sa为排位第k的后缀开头在哪里
//rank为开头位置在k的后缀的排名 
void da(int *r,int n,int m)//m是最大ASCII 
{
	int p,*x=wa,*y=wb,*t;//x≈rank, y≈第二关键字 
	//x的实际意义就是当前所对应的ASCII值 
	for(int i=0;i<m;i++)wd[i]=0; 
	for(int i=0;i<n;i++)wd[x[i]=r[i]]++;//x[i]初始排名 
	for(int i=1;i<m;i++)wd[i]+=wd[i-1];
	for(int i=n-1;i>=0;i--)sa[--wd[x[i]]]=i;
	//计数排序 
	//这一段wd是一个辅助工具,初始化为0
	//先统计ASCII为r[i]的个数,累加计数,再排名
	//排位i的字符是x[i] wd[x[i]]是位置贡献 
	//sa[]=i表示排名xx的位置在i
	
	for(int k=1;k<=n;k<<=1)//每次的合并长度为k 
	{
		p=0;
		//对第二关键字进行排序
		//第一步- 后面有一段没有,填0 
		for(int i=n-k;i<n;i++)y[++p]=i;
		//☆由于这边是空串,就第2关键字而言,空串一定会排到前面(填0)
		for(int i=0;i<n;i++)if(sa[i]>=k)y[++p]=sa[i]-k;//某个位置左移k位存在,
		//那么它可以作为第2关键字,
		//由于之前从小到大排所以它也是按一定顺序插入的  
		
		//之后对第一关键字排序  类似于第一次计数排序 
		for(int i=0;i<m;i++)wd[i]=0;
		for(int i=0;i<n;i++)wd[x[y[i]]]++;//排名第i位(y[i])位置的x[]值的个数统计
		for(int i=1;i<m;i++)wd[i]+=wd[i-1];
		for(int i=n-1;i>=0;i--)sa[--wd[x[y[i]]]]=y[i]; //排名为i的位置y[i]对应ASCII值的对应位置贡献 
		//sa[这个贡献]=y[i]表示排名为这个贡献的后缀第一个位置
		
		swap(x,y);//明白了,是这个意思:因为下次我们还要使用x,x是要更新的
		//而更新时需要用到某些之前信息,就让y暂时储存x的信息 
				
		//我们还要做的工作是检查是否排序完成
		//并且优化最大ASCII值
		p=1,x[sa[0]]=0; 
		for(int 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;//优化最大ASCII值 
	}  
}
//在已经排好的sa[]数组可以得到rank[]
//rank代表第i开头的后缀的排名
//height代表的意思是相连两个排名的公共前缀
//有以下性质height[i]>=height[i-1]-1 
void getheight()
{
	int i,j,k=0;
	for(i=1;i<=n;i++)rank[sa[i]]=i;
	for(i=0;i<n;i++)
	{
		if(k)k--;//利用性质 
		j=sa[rank[i]-1];
		//位置i和它排名的前一个所对应的位置
		while(s[i+k]==s[j+k])k++;
		height[rank[i]]=k; 
	}
}
int main()
{
	
	return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值