字尾陣列倍增構造演算法說解

2021-07-28 06:07:51 字數 1991 閱讀 5790

字尾陣列,作為一種高效的字串處理資料結構,沒有雜湊演算法的隨機性,也沒有 kmp 演算法的侷限性,是作為一種較為全面而程式設計思想不甚複雜的資料結構加以應用。字尾陣列應用最為廣泛的一種構建方法是倍增構造,時間複雜度為 o(nlogn),其中 n 為待處理字串的長度。

我們不妨設待處理的字串儲存在 s[1 .. n] 中,則在乙個字尾陣列 sa[1 .. n] 中,sa[i] 表示該字串的所有字尾集合 中字典序為 i 的字尾為 s[sa[i] .. n]。與之相對應的字尾名次數組 rank[1 .. n] 中,rank[i] 表示字尾 s[i .. n] 在該字串的所有字尾集合 中的字典序排名為 rank[i]。顯然,rank[sa[i]] = sa[rank[i]] = i。

倍增演算法究其本質,類似於歸併排序的過程。當第 i 輪倍增結束後,演算法保證原字串的所有字尾已經按前 2i

位字典序有序排列。我們設 rank[i][1 .. n] 表示第 i 輪倍增後的字尾名次數組,則先預處理出 rank[0][1 .. n] 的值(元素相同時排名相同)。假設我們已經處理完 rank[i][1 .. n] 的值,此時若想處理出 rank[i + 1][1 .. n] 的值,對於第 j 個元素,我們只需以 rank[i][j] 為第一關鍵字,以 rank [i][j + 2i

] 為第二關鍵字排序,並重新編號名次即可。

對於以上過程成立的原因,我們可以如此考慮。rank[i][j] 表示 s[j .. j + 2i

- 1] 的排名,rank [i][j + 2i

] 表示 s[j + 2i

.. j + 2i

+1- 1] 的排名,排序過程相當於以 s[j .. j + 2i

- 1] 為第一關鍵字,以 s[j + 2i

.. j + 2i

+1- 1] 為第二關鍵字排序,即以 s[j .. j + 2i

+1- 1] 按字典序排序,重編號後的結果就是 rank[i+1][j] 的值。

在每一輪倍增過程的排序中,若使用快排,則每輪倍增的時間複雜度為 o(nlogn),整個倍增過程的時間複雜度為 o(nl

og2n

)。考慮到 rank[1 .. n] 中的元素不超過 n,我們可以使用基數排序來降低時間複雜度,使得每輪倍增的時間複雜度為 o(n),從而使整個倍增過程的時間複雜度為 o(nlogn)。

每一輪基數排序的過程中,都會進行兩次計數排序。第一次計數排序,以第二關鍵字對當前名次陣列排序,將排序結果儲存在索引陣列裡。第二次計數排序,以索引陣列為遍歷順序,以第一關鍵字對當前名次陣列排序,將排序結果儲存在當前字尾陣列裡。這樣可以保證基數排序的正確性。計數排序的**如下:

#define countsort(_rank,_sa,_index,_n,_m,_incr) \

基數排序後,要對名次陣列重編號,其中第一關鍵字和第二關鍵字對應相同的元素,名次也應相同。由於基數排序處理出當前字尾陣列,所以可以用當前字尾陣列將當前名次陣列處理出來。具體方法是,必然有 rank[sa[i - 1]] = rank[sa[i]] 或 rank[sa[i - 1]] + 1 = rank[sa[i]]。重編號的**如下:

#define reorder(_rank,_sa,_index,_n,_m,_incr) \

在倍增演算法之前,先將字元轉成數字儲存在名次陣列裡,再用一次重編號將 rank[0][1 .. n] 處理出來。在倍增演算法的過程中,若增量 i 大於等於 n 或重編號後的最大名次等於 n,則可以確定字尾陣列已經構造完成。倍增演算法的**如下:

char s[max_n];

int height[max_n],count[max_n],n,rank[max_n],sa[max_n];

void doubling()

m=0;

for(int i=1;i<=n;height[rank[i++]]=m)

for(m?m--:0;s[i+m]==s[sa[rank[i]-1]+m];m++);

}

字尾陣列 倍增演算法模板

關於字尾陣列的資料,可以看noi2009國家集訓隊 羅穗騫 的 字尾陣列 處理字串的有力工具 suffix array 倍增演算法 o n lgn build sa n 1,注意n 1 getheight n n 8 num 注意num陣列最後一位值為0,其它位須大於0 rank rank 0 n ...

利用倍增演算法的字尾陣列

仍然不是很懂,貼篇文章放在這兒希望有朝一日能頓悟吧。老天,乙個字尾陣列不知道看了多少天,最後終於還是看懂了啊!最關鍵的就是一會兒下標表示排名,一會用數值表示排名繞死人了。我不知道手跑了多少次才明白過來。其實我也建議初學者手跑幾遍,但是一定要注意陣列的意義,否則就是無用功。s 輸入的字串,預處理的時候...

字尾陣列倍增演算法模板詳解

2009國家集訓隊 字尾陣列 處理字串的有力工具 羅穗騫 bool cmp int r,int a,int b,int l void init int r,int sa,int n,int m for i 0 i n i rk sa i i int k 0 for i 0 i n 1 h rk i ...