仍然不是很懂,貼篇文章放在這兒希望有朝一日能頓悟吧。
老天,乙個字尾陣列不知道看了多少天,最後終於還是看懂了啊!
最關鍵的就是一會兒下標表示排名,一會用數值表示排名繞死人了。
我不知道手跑了多少次才明白過來。其實我也建議初學者手跑幾遍,但是一定要注意陣列的意義,否則就是無用功。
s[ ]:輸入的字串,預處理的時候會在末尾加上乙個0
sa[ ]:它的下標就是字尾排名
x[ ] = t[ ]:用來儲存第一關鍵字排名,注意!它的數值是排名。初始時恰好是字串的ascii碼。字典序嘛!
y[ ] = t2[ ]:它的下標就是第二關鍵字排名,第二關鍵字是直接從sa[ ]當中提取的,關係極其密切
c[ ]:用來基數排序。初始值恰好是每種字元出現的次數。後來它的作用就跟基數排序密切相關,建議學習基數排序
有一點一定要注意!第二關鍵字來自sa[ ]陣列,但是第一關鍵字並不是來自sa[ ]陣列!這一點不知道迷惑了多少人,就是因為**裡給出的圖完全就是原理圖,不是**實現的圖,不搭噶的!
p.s. 為了優化時間空間,避免新開乙個中間陣列來複製t[ ]的值,採用了將它的指標x和t2[ ]的指標y交換的方法。注意這個時候t2[ ]已經沒有用了。
[cpp]view plain
copy
?#include
#include
#include
using
namespace
std;
const
intn = 1000, m = 130;
char
s[n];
intsa[n], t[n], t2[n], c[m], n;
intrank[n], high[n];
#define dbg
#ifdef dbg
intdb[n];
void
debug(
int*f)
printf("%3d"
, db[0]);
for(
inti = 1; i
);
} #endif
bool
cmp(
int*y,
inti,
intk)
void
build(
intm)
puts("}"
);
#endif
//x的內容就是對應的第一關鍵字排名
//根據x的內容和y的下標進行合併,得到新的排名作為sa的下標
for(i = 0; i
for(i = 0; i
for(i = 1; i
for(i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
#ifdef dbg
printf("sa get:["
);
debug(sa);
puts(""
);
#endif
//按照sa的順序提取出老的x,計算新的x
swap(x, y);
p = 1; x[sa[0]] = 0;//sa[0]一定是新增的字元0,排名萬年第0
for(i = 1; i
//剪枝,此時x中已經沒有相同的值,sa被確定
if(p >= n)
break
; }
} void
get_high()
} void
pr()
intmain()
s[n-1] = 0;
build(maxi+1);
get_high();
#ifdef dbg
pr();
#endif
return
0;
}
根據這份**,輸入一些資料測試一下,仔細研究研究中間輸出。
方框代表裡面的值是下標,花括號代表是數值。它們都是和第一行紅色數字一一對應的。
我們暫時不去管第一關鍵字是怎樣計算出來的。
根據上面的程式,自己來填寫這張圖當中的數值。乙個乙個填寫就可以明白了。(x[ ]陣列的值就直接看圖上的,並且注意每乙個x[ ]陣列都是在上一層基數排序計算出來的)
sa[ ]的初始值恰好是根據字元出現次數乙個乙個來的,輕易就可以手跑出來。這就完成了一位數的基數排序。
藍色的字是第二關鍵字,正好是從sa[ ]當中提取出來的。黃色的箭頭表示沒有第二關鍵字,它們的排名是自左向右從0開始填的,要先填完這個再提取其他的第二關鍵字。再次強調,雖然有線,但是第一關鍵字並不是sa[ ]陣列當中的數!
然後給出的x[ ]和剛填完的y[ ]合併(綠色字型),計算出sa[ ]。這是兩位數的基數排序。
接下來繼續倍增,完成四位數的基數排序。(如果你困惑為什麼還是只有兩個數被線指著,建議閱讀**)
最後,其實本來是不用對八位數進行基數排序,因為這個時候新的x[ ]陣列(圖中倒數第二行)裡面已經沒有重複的排名了,而第一關鍵字是首要的,因此sa[ ]陣列被確定下來了。這裡可以加個剪枝,break一下。
在每一次得到sa[ ]陣列之後,計算新的x[ ],方法是按照sa[ ]當中的排名順序,(即sa[1...n])提取出舊的x[ ](注意此時它的名字叫做y[ ]了)來計算。如果某字串跟之前的那個完全一樣(即cmp()函式),排名就一樣(p-1)。
根據上面的話,再來自己填寫x[ ]陣列吧!
字尾陣列 倍增演算法模板
關於字尾陣列的資料,可以看noi2009國家集訓隊 羅穗騫 的 字尾陣列 處理字串的有力工具 suffix array 倍增演算法 o n lgn build sa n 1,注意n 1 getheight n n 8 num 注意num陣列最後一位值為0,其它位須大於0 rank rank 0 n ...
字尾陣列倍增演算法模板詳解
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 ...
字尾陣列倍增法
字尾陣列 字尾陣列是處理字串的有力工具。字尾陣列是字尾樹的乙個非常精巧的替代品,它比字尾樹容易程式設計實現,能夠實現字尾樹的很多功能而時間複雜度也並不遜色,而且它比字尾樹所占用的記憶體空間小很多。可以說,在資訊學競賽中字尾陣列比字尾樹要更為實用。1.1 基本定義 子串 字串s的子串r i.j i j...