双数组trie原理
這個(gè)算法的本質(zhì)就是將Trie樹(shù)結(jié)構(gòu)簡(jiǎn)化為兩個(gè)線(xiàn)性數(shù)組,如圖2所示。
base數(shù)組和數(shù)組中的元素是一一對(duì)應(yīng)的,base數(shù)組中的每一個(gè)元素相當(dāng)于Trie樹(shù)的一個(gè)節(jié)點(diǎn),其值做狀態(tài)轉(zhuǎn)移的基值,check值相當(dāng)于校驗(yàn)值,用于檢查該狀態(tài)是否存在。對(duì)于從狀態(tài)
s到狀態(tài)t的一個(gè)轉(zhuǎn)移,必須滿(mǎn)足如下兩個(gè)條件:
1.base[s]+c=t
2.check[ t] =s
其中c是輸入變量。
數(shù)組構(gòu)造完成之后,要查找一個(gè)關(guān)鍵碼Ab是很快,只需要一步加法,即只需判斷check[base[A]+b]是否等于A.狀態(tài)A有個(gè)基值,為base[A],則Ab所在的節(jié)點(diǎn)應(yīng)該為基值+輸入狀態(tài),即base[A]+b,可以這么認(rèn)為,Ab的節(jié)點(diǎn)為base[A]+b,同樣這個(gè)節(jié)點(diǎn)也存在相應(yīng)的基值。
同理要查找abc是否在詞典中,只需判斷check[base[base[a]+b]+c]是否等于base[a]+b
雙數(shù)組trie樹(shù)的構(gòu)造過(guò)程,稍微麻煩點(diǎn),詳細(xì)請(qǐng)參考:http://linux.thai.net/~thep/datrie/datrie.html
假設(shè)這樣一個(gè)場(chǎng)景,ab,ac,ae已經(jīng)放入trie中,這時(shí)要插入ad, base[ base[a]+d ] !=0,說(shuō)明ad節(jié)點(diǎn)的位置已經(jīng)被其他的詞占了,譬如是ec。這個(gè)時(shí)候要調(diào)整a的基值,即base[a].如果要調(diào)節(jié)base[a]就要考慮到,ab,ac,ae的值要改變,同時(shí)abe的值也會(huì)改變。算法如下:
其中,s就是例子中的a,本來(lái)base[a]=t,但是插入ad時(shí),位置已經(jīng)被其他詞占了,譬如ec,所以這時(shí)要調(diào)整base[a]的值,調(diào)整為base[a] = b,至于b是如果得到的,請(qǐng)繼續(xù)研究。。。。
因?yàn)楝F(xiàn)在base[s]=b,所以詞sb,sc,se所對(duì)應(yīng)的節(jié)點(diǎn)下標(biāo)要改變,如行2所示;本來(lái)sb,sc,se對(duì)應(yīng)的下標(biāo),即節(jié)點(diǎn)為base[s]+b,base[s]+c,base[s]+e,現(xiàn)在要改為b+b,b+c,b+e
因?yàn)閟b,se,sc移到了新位置,所以check要更新,如行1所示;指示sb,sc,se的新節(jié)點(diǎn)為b+b,b+c,b+e,但是他們的上一個(gè)節(jié)點(diǎn)還是s
改變sc的值,那scd的節(jié)點(diǎn)也要變化,要主要到scd的節(jié)點(diǎn)對(duì)應(yīng)的下標(biāo)沒(méi)有變化,base[base[s]+c] +d ,雖然s的基值變?yōu)榱薭,但是sc的基值還是不變,但是ac的下表變了,所以要更新acd上一個(gè)狀態(tài)對(duì)應(yīng)的下標(biāo),只要更新check[base[ base[s]+c]+d],使其指向下標(biāo)b+c;如行3 所示
Procedure Relocate(s : state; b : base_index)
{ Move base for state s to a new place beginning at b }
begin
? ? foreach input character c for the state s
? ? { i.e. foreach c such that check[base[s] + c]] = s }
? ? begin
? ? ? ? check[b + c] := s; ? ? { mark owner }//1
? ? ? ? base[b + c] := base[base[s] + c]; ? ? { copy data }//2
? ? ? ? { the node base[s] + c is to be moved to b + c;
? ? ? ? ? Hence, for any i for which check[i] = base[s] + c, update check[i] to b + c }
? ? ? ? foreach input character d for the node base[s] + c
? ? ? ? begin
? ? ? ? ? ? check[base[base[s] + c] + d] := b + c//3
? ? ? ? end;
? ? ? ? check[base[s] + c] := none ? ? { free the cell }
? ? end;
? ? base[s] := b
end
從圖中可以看出,下標(biāo)s的基值變?yōu)閎,即虛線(xiàn)所指
對(duì)應(yīng)sc的下標(biāo)從t變?yōu)閠',要更新check[t'] = s,check[u] = t'
//
筆試題:
請(qǐng)?jiān)O(shè)計(jì)一個(gè)字典。以字符串為索引,存儲(chǔ)用戶(hù)定義的定長(zhǎng)結(jié)構(gòu)。要求有增、刪、查、改的功能。已經(jīng)給定一個(gè)函數(shù),可以由字符串映射到一個(gè)簽名,每個(gè)簽名由兩個(gè)unsigned int類(lèi)型組成。假設(shè)每一個(gè)字符串能夠?qū)?yīng)唯一的一個(gè)簽名,完全沒(méi)有重復(fù)(或者重復(fù)的概率可以忽略),并且簽名分布足夠均勻。
最直接的想法就是構(gòu)造一個(gè)兩層的trie樹(shù)
還可以用hash來(lái)做,用第一個(gè)unsigned int作為hash的key,將key相等的詞的第二個(gè)unsigned int安裝順序排序,這樣可以用二分查找法查找
map<int, map<int, data>>
總結(jié)