快速排序更容易理解,直接写一个二元组的比较函数,用sort排序就可以了,每次排序时间复杂度,总的时间复杂度是,一般这个复杂度是可以接受的
题目:
C++代码实现:
#include <bits/stdc++.h>
using namespace std;
#define maxn 1000009
typedef long long int ll;
string str;//给定的字符串
//string Suffix[maxn];//保存字符串后缀,在不需要输出后缀的情况下最好不加这个数组,加上可能会爆内存
int n;//字符串的大小
int Sa[maxn];//所求的后缀数组
int Rank[maxn];//表示后缀排第几的数组
int tp[maxn];//临时存储Rank的值
int k=0;
/*void get_Suffix()//得到字符串的后缀
{
Suffix[n]=str[n];
for(int i=n-1;i>=1;i--)
Suffix[i]=str[i]+Suffix[i+1];
}*/
bool comp(int x,int y)//
{
if(Rank[x]!=Rank[y])//先比较第一关键字
return Rank[x]<Rank[y];
//比较第二关键字,如果超出n则补为-1,防止数组越界
int rx=x+k>n?-1:Rank[x+k];
int ry=y+k>n?-1:Rank[y+k];
return rx<ry;
}
bool judge(int x,int y)//判断后缀x,y的二元组是否相等
{
if(Rank[x]==Rank[y])//先比较第一关键字
{
//比较第二关键字,如果超出n则补为-1,防止数组越界
int rx=x+k>n?-1:Rank[x+k];
int ry=y+k>n?-1:Rank[y+k];
if(rx==ry)
return 1;
return 0;
}
return 0;
}
void get_Sa()
{
memset(Rank,0,sizeof(Rank));
for(int i=1;i<=n;i++)//初始化
{
Sa[i]=i;
Rank[i]=str[i];//第一次的Rank就是后缀的第一个字符,字符的大小就可代表后缀的Rank
}
for(k=1;k<=n;k<<=1)
{
sort(Sa+1,Sa+n+1,comp);//根据二元组排序
int fg=0;//fg表示目前的最大次序号,每次初始为0
for(int i=1;i<=n;i++)//按照Sa从小到大给后缀更新次序
{
if(judge(Sa[i],Sa[i-1])==0)//如果与前一个二元组不相同,则产生新的次序号,将fg+1
fg++;
tp[Sa[i]]=fg;
}
for(int i=1;i<=n;i++)
Rank[i]=tp[i];
if(fg>=n)//最大次序号大于等于n,说明每个后缀都有一个不同的次序号就结束
break;
}
return ;
}
int main()
{
cin>>str;
n=str.size();
str=" "+str;//使字符串编号是1到n
get_Sa();
for(int i=1;i<n;i++)
cout<<Sa[i]<<" ";
cout<<Sa[n]<<endl;
return 0;
}