1. 程式人生 > >字尾陣列的快速排序實現

字尾陣列的快速排序實現

快速排序

這種排序方法更容易理解,直接寫一個二元組的比較函式,用sort排序就可以了,每次排序時間複雜度O(n*logn),總的時間複雜度是,一般這個複雜度是可以接受的

題目:

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