後綴數組-入門學習

後綴數組論文鏈接——處理字符串的有力工具_百度文庫

後綴排序

Description

Tim正在自學《數據結構》,他剛剛學會如何比較兩個字符串大小。書上是這麼說的(和Pascal語言中的比較規則相同,學習過Pascal語言的同學可以跳過這段): 
比較兩個不同字符串s1=’p1p2p3…pN’和s2=’q1q2q3…qM’的大小,設N<=M。 
若s1是s2的前綴,則s1<s2。否則設pi<>qi,且i最小;若pi<qi,則s1<s2,否則s1>s2。 
Tim想通過練習熟練運用這個規則,於是打算出許多字符串,並將它們從小到大排序。可是Tim非常懶,隨機寫出 K個很長的字符串實在是太麻煩了。不過聰明的他想到了一個好辦法,他寫了一個很長的字符串,自言自語說,“我只要把這個字符串的所有後綴從小到大排序就可以了”。 

Input

輸入文件suffix.in中僅有一行,且是一個僅包含小寫字母的字符串,長度K不超過10^5。 

Output

有K行,每行一個數字,第i行的數字Pi表示所有後綴中,第i小的是由原字符串第Pi個字符引導的後綴。 

Sample Input

 

mississippi

 

Sample Output

 

11 8 5 2 1 10 9 7 4 6 3

-----------------------------------------------------------------------------------------     分割線    ------------------------------------------------------------------------------------------------------------------------------

 code

#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<set>
#include<map>
#include<list>
#include<queue>
#include<deque>
#include<stack>
#include<string>
#include<vector>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<time.h>

using namespace std;
typedef long long LL;
const int INF=2e9+1e8;
const int MOD=1e9+7;
const int MAXSIZE=1e6+5;
const double eps=0.0000000001;
void fre()
{
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
}
#define memst(a,b) memset(a,b,sizeof(a))
#define fr(i,a,n) for(int i=a;i<n;i++)

int rankarr[MAXSIZE],wa[MAXSIZE],wb[MAXSIZE],height[MAXSIZE];
int wvarr[MAXSIZE],wsarr[MAXSIZE],SA[MAXSIZE];
char str[MAXSIZE];

int cmp(int *r,int a,int b,int l)
{
    return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(char *r,int *sa,int n,int m)
{
    int i,j,p,*x=wa,*y=wb,*t;
    for(i=0; i<m; i++) wsarr[i]=0;
    for(i=0; i<n; i++) wsarr[x[i]=r[i]]++;
    for(i=1; i<m; i++) wsarr[i]+=wsarr[i-1];
    for(i=n-1; i>=0; i--) sa[--wsarr[x[i]]]=i;
    for(j=1,p=1; p<n; j<<=1,m=p)
    {
        for(p=0,i=n-j; i<n; i++) y[p++]=i;
        for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j;
        for(i=0; i<n; i++) wvarr[i]=x[y[i]];
        for(i=0; i<m; i++) wsarr[i]=0;
        for(i=0; i<n; i++) wsarr[wvarr[i]]++;
        for(i=1; i<m; i++) wsarr[i]+=wsarr[i-1];
        for(i=n-1; i>=0; i--) sa[--wsarr[wvarr[i]]]=y[i];
        for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    }
    return;
}
void calheight(char *r,int *sa,int n)
{
    int i,j,k=0;
    for(i=1; i<=n; i++) rankarr[sa[i]]=i;
    for(i=0; i<n; height[rankarr[i++]]=k)
        for(k?k--:0,j=sa[rankarr[i]-1]; r[i+k]==r[j+k]; k++);
    return;
}
int main()
{
    while(gets(str))
    {
        int n=strlen(str);
        str[n]=0;
        da(str,SA,n+1,128); //值得注意是 n+1
        calheight(str,SA,n);
        for(int i=1; i<=n; i++) printf("%d ",SA[i]);
        printf("\n");
        for(int i=0; i<n; i++) printf("%d ",rankarr[i]);
        printf("\n");
    }
    return 0;
}

這個字符串下標從 0~ n-1 

這個代碼 rank[a]=b 表示suffix(a)的排名是 b   (注意:排名第一不是0,而是 1 ) 

 所以  rank[i]      0 <= i < n   

則      SA[i]         1<= i <= n

  排名是1到n   數組下標是0 到 n-1。



/***
DC3 算法:
相關數組開3倍大,SA,r 數組也是。
用法與DC3 一樣。末尾添加0字符,插入的特殊字符串不能和末尾
字符相同。dc3 傳參數長度需要 +1 。注意int 與 char

*/


#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
int SA[MAXSIZE],Rank[MAXSIZE],height[MAXSIZE];
int wa[MAXSIZE],wb[MAXSIZE],wv[MAXSIZE],wss[MAXSIZE];
int c0(int *r,int a,int b)
{
    return r[a] == r[b] && r[a+1] == r[b+1] && r[a+2] == r[b+2];
}
int c12(int k,int *r,int a,int b)
{
    if(k == 2)
        return r[a] < r[b] || ( r[a] == r[b] && c12(1,r,a+1,b+1) );
    else return r[a] < r[b] || ( r[a] == r[b] && wv[a+1] < wv[b+1] );
}
void sort(int *r,int *a,int *b,int n,int m)
{
    int i;
    for(i = 0; i < n; i++)wv[i] = r[a[i]];
    for(i = 0; i < m; i++)wss[i] = 0;
    for(i = 0; i < n; i++)wss[wv[i]]++;
    for(i = 1; i < m; i++)wss[i] += wss[i-1];
    for(i = n-1; i >= 0; i--)
        b[--wss[wv[i]]] = a[i];
}
void dc3(int *r,int *sa,int n,int m)
{
    int i, j, *rn = r + n;
    int *san = sa + n, ta = 0, tb = (n+1)/3, tbc = 0, p;
    r[n] = r[n+1] = 0;
    for(i = 0; i < n; i++)if(i %3 != 0)wa[tbc++] = i;
    sort(r + 2, wa, wb, tbc, m);
    sort(r + 1, wb, wa, tbc, m);
    sort(r, wa, wb, tbc, m);
    for(p = 1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++)
        rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p - 1 : p++;
    if(p < tbc)dc3(rn,san,tbc,p);
    else for(i = 0; i < tbc; i++)san[rn[i]] = i;
    for(i = 0; i < tbc; i++) if(san[i] < tb)wb[ta++] = san[i] * 3;
    if(n % 3 == 1)wb[ta++] = n - 1;
    sort(r, wb, wa, ta, m);
    for(i = 0; i < tbc; i++)wv[wb[i] = G(san[i])] = i;
    for(i = 0, j = 0, p = 0; i < ta && j < tbc; p++)
        sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++];
    for(; i < ta; p++)sa[p] = wa[i++];
    for(; j < tbc; p++)sa[p] = wb[j++];
}


void calheight(int *r,int *sa,int n)
{
    int i,j,k=0;
    for(i=1; i<=n; i++) Rank[sa[i]]=i;
    for(i=0; i<n; height[Rank[i++]]=k)
        for(k?k--:0,j=sa[Rank[i]-1]; r[i+k]==r[j+k]; k++);
    return;
}



發佈了100 篇原創文章 · 獲贊 46 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章