字尾陣列 處理字串的有力工具

2021-06-18 02:50:20 字數 2359 閱讀 6181

字尾陣列——處理字串的有力工具

2009年1月

【摘要】

字尾陣列是處理字串的有力工具。字尾陣列是字尾樹的乙個非常精巧的替代品,它比字尾樹容易程式設計實現,能夠實現字尾樹的很多功能而時間複雜度也並不遜色,而且它比字尾樹所占用的記憶體空間小很多。可以說,在資訊學競賽中字尾陣列比字尾樹要更為實用。本文分兩部分。第一部分介紹兩種構造字尾陣列的方法,重點介紹如何用簡潔高效的**實現,並對兩種演算法進行了比較。第二部分介紹字尾陣列在各種型別題目中的具體應用。

【關鍵字】

字串,字尾,字尾陣列,名次陣列,基數排序,

【正文】

一、字尾陣列的實現

本節主要介紹字尾陣列的兩種實現方法:倍增演算法(doubling algorithm)和dc3演算法(difference cover),並對兩種演算法進行了比較。可能有的讀者會認為這兩種演算法難以理解,即使理解了也難以用程式實現。本節針對這個問題,在介紹這兩種演算法的基礎上,還給出了簡潔高效的**。其中倍增演算法只有25行,dc3演算法只有40行。

1.1、基本定義

子串:字串s的子串r[i..j],i≤j,表示r串中從i到j這一段,也就是順次排列r[i],r[i+1],...,r[j]形成的字串。

字尾:字尾是指從某個位置i開始到整個串末尾結束的乙個特殊子串。字串r的從第i個字元開始的字尾表示為suffix(i),也就是suffix(i)=r[i..len(r)]。

大小比較:關於字串的大小比較,是指通常所說的「字典順序」比較,也就是對於兩個字串u、v,令i從1開始順次比較u[i]和v[i],如果u[i]=v[i]則令i加1,否則若u[i]v[i]則認為u>v(也就是vlen(u)或者 i>len(v)仍比較不出結果,那麼若len(u)len(v)則 u>v。

從字串的大小比較的定義來看,s的兩個開頭位置不同的字尾 u和v進行比較的結果不可能是相等,因為 u=v的必要條件len(u)=len(v)在這裡不可能滿足。

字尾陣列:字尾陣列sa是乙個一維陣列,它儲存1..n的某個排列sa[1],sa[2],……,sa[n],並且保證 suffix(sa[i])=0;i--) sa[--ws[x[i]]]=i; 

for(j=1,p=1;p=j) y[p++]=sa[i]-j; 

for(i=0;i=0;i--) sa[--ws[wv[i]]]=y[i]; 

for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i=0;i--) sa[--ws[x[i]]]=i;

這裡x陣列儲存的值相當於是rank值。下面的操作只是用x陣列來比較字元的大小,所以沒有必要求出當前真實的rank值。

接下來進行若干次基數排序,在實現的時候,這裡有乙個小優化。基數排序要分兩次,第一次是對第二關鍵字排序,第二次是對第一關鍵字排序。對第二關鍵字排序的結果實際上可以利用上一次求得的sa直接算出,沒有必要再算一次。**:

for(p=0,i=n-j;i=j) y[p++]=sa[i]-j;

其中變數j是當前字串的長度,陣列y儲存的是對第二關鍵字排序的結果。然後要對第一關鍵字進行排序,**:

for(i=0;i=0;i--) sa[--ws[wv[i]]]=y[i];

這樣便求出了新的sa值。在求出sa後,下一步是計算rank值。這裡要注意的是,可能有多個字串的rank值是相同的,所以必須比較兩個字串是否完全相同,y陣列的值已經沒有必要儲存,為了節省空間,這裡用y陣列儲存rank值。這裡又有乙個小優化,將x和y定義為指標型別,複製整個陣列的操作可以用交換指標的值代替,不必將陣列中值乙個乙個的複製。**:

for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i=0;i--) b[--ws[wv[i]]]=a[i]; 

return; 

}void dc3(int *r,int *sa,int n,int m)

基數排序結束後,新的字元的排名儲存在 wb陣列中。

跟倍增演算法一樣,在基數排序以後,求新的字串時要判斷兩個字元組是否完全相同。**:

for(p=1,rn[f(wb[0])]=0,i=1; i1,如果h[i-1]≤1,原式顯然成立)並且suffix(k+1)和suffix(i)的最長公共字首是h[i-1]-1,所以suffix(i)和在它前一名的字尾的最長公共字首至少是h[i-1]-1。按照h[1],h[2],……,h[n]的順序計算,並利用h陣列的性質,時間複雜度可以降為o(n)。

具體實現:

實現的時候其實沒有必要儲存h陣列,只須按照h[1],h[2],……,h[n]的順序計算即可。**:

int rank[maxn],height[maxn];

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

演算法合集之《字尾陣列 處理字串的有力工具》

字尾陣列 sa i 表示排名第i個的首字母位置 rank i 第i個數的排名 height i sa i 和sa i 1 的最長公共字首 suffix j 和suffix k 的最長公共字首為height rank j 1 height rank j 2 height rank j 3 height...

字尾陣列 用字尾處理字串

字尾陣列處理的是文字串。我們將文字串的每一條字尾拿出來,按照字典序排序,然後就可以處理字尾陣列了。字尾陣列sa i 表示的就是排名第i位的字尾的第乙個字元所在下標。這可能有點繞口,所以我們用樣例解釋一下,如對於文字串ababa,則字尾為ababa,baba,aba,ba,a,我們排序後就是 a,ab...

字串 字尾陣列

n 字串的長度。m 當前字尾 離散化後 的值域。對於char可以跳過離散化,初值取128即可,對於int要離散化,初值取n即可,初值要保證覆蓋整個值域。sa i 排名為 i 的字尾的起始位置。rk i 起始位置為 i 的字尾的排名。驗證 const int maxn 1000000 10 int n...