后缀数组的快速排序实现

快速排序更容易理解,直接写一个二元组的比较函数,用sort排序就可以了,每次排序时间复杂度O(n*logn),总的时间复杂度是,一般这个复杂度是可以接受的

题目:

落谷P3809【模板】后缀数组

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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值