ref : https://dsqiu.iteye.com/blog/1705697
算法
1.Trie導引數組
Trie樹是一種基於樹的數據結構,又稱單詞查找樹、前綴樹,是一種哈希樹的變種。應用於字符串的統計與排序,常常被搜索引擎系統用於文本詞頻統計。用於存儲字符串以便支持快速模式匹配,主要應用在信息檢索中,Trie支持的主要查詢操做是模式匹配和前綴匹配。Trie樹能夠看着是一個肯定有限狀態自動機,有限狀態自動機另外一篇博文字符串模式匹配算法——BM、Horspool、Sunday、KMP、KR、AC算法一網打盡 有介紹。數據結構
2.標準Trie性能
令S是取自字母表∑的s個集合,知足S中不存在一個串是另外一個串的前綴。S的一個標準Trie(standard trie)是一顆有序書T,知足以下性質:搜索引擎
下圖是串{bear,bell,bid,bull,buy,sell,stock,stop}的標準Triespa
存儲總長爲n,來自大小爲d的字母表中s個串的集合S的標準Trie具備以下性質:指針
性能:對於有n個英文字母的串來講,在內部結點中定位指針所須要花費O(d)時間,d爲字母表的大小,英文爲26。因爲在上面的算法中內部結點指針定位使用了數組隨機存儲方式,所以時間複雜度降爲了O(1)。可是若是是中文字,下面在實際應用中會提到。所以咱們在這裏仍是用O(d)。 查找成功的時候剛好走了一條從根結點到葉子結點的路徑。所以時間複雜度爲O(d*n)。可是,當查找集合X中全部字符串兩兩都不共享前綴時,trie中出現最壞狀況。除根以外,全部內部結點都自由一個子結點。此時的查找時間複雜度蛻化爲O(d*(n^2))code
中文詞語的標準Trie樹blog
因爲中文的字遠比英文的26個字母多的多。所以對於trie樹的內部結點,不可能用一個26的數組來存儲指針。若是每一個結點都開闢幾萬個中國字的指針空間。估計內存要爆了,就連磁盤也消耗很大。排序
通常咱們採起這樣種措施:
(1) 以詞語中相同的第一個字爲根組成一棵樹。這樣的話,一箇中文詞彙的集合就能夠構成一片Trie森林。這篇森林都存儲在磁盤上。森林的root中的字和root所在磁盤的位置都記錄在一張以Unicode碼值排序的有序字表中。字表能夠存放在內存裏。
(2) 內部結點的指針用可變長數組存儲。
特色:因爲中文詞語不多操做4個字的,所以Trie樹的高度不長。查找的時間主要耗費在內部結點指針的查找。所以將這項指向字的指針按照字的Unicode碼值排序,而後加載進內存之後經過二分查找可以提升效率。
標準Trie的應用舉例
標準Trie的應用和優缺點
(1) 全字匹配:肯定待查字串是否與集合的一個單詞徹底匹配。
(2) 前綴匹配:查找集合中與以s爲前綴的全部串。
注意:Trie樹的結構並不適合用來查找子串。這一點和前面提到的PAT Tree以及後面專門要提到的Suffix Tree的做用有很大不一樣。
優勢: 查找效率比與集合中的每個字符串作匹配的效率要高不少。在o(m)時間內搜索一個長度爲m的字符串s是否在字典裏。
缺點:標準Trie的空間利用率不高,可能存在大量結點中只有一個子結點,這樣的結點絕對是一種浪費。正是這個緣由,才迅速推進了下面所講的壓縮trie的開發。
壓縮Trie
壓縮Trie相似於標準Trie,但它能保證Trie中的每一個內部結點至少有兩個字結點。經過把單子結點鏈壓縮進各條邊中來執行這個規則。設T是一棵標準Trie,若是T的一個內部結點v有一個子結點且它不是根,則稱爲這個內部結點是內部結點是冗餘的(redundant)。
若是
串{bear,bell,bid,bull,buy,sell,stock,stop}的壓縮Trie
壓縮Trie的性質和優點:
與標準Trie比較,壓縮Trie的結點數與串的個數成正比了,而不是與串的總長度成正比。一棵存儲來自大小爲d的字母表中的s個串的結合T的壓縮trie具備以下性質:
(1) T中的每一個內部結點至少有兩個子結點,至多有d個子結點。
(2) T有s個外部結點。
(3) T中的結點數爲O(s)
存儲空間從標準Trie的O(n)下降到壓縮後的O(s),其中n爲集合T中總字符串長度,s爲T中的字符串個數。
壓縮Trie應用舉例
假定串的集合S是S[0],S[1],...,S[s-1]的一個數組,使用三元組(i,j,k)隱式地表示存儲的標記X,知足X=S[i][j,...,k];即X是S[i]的子串,由從j到k所包含的字符組成。
後綴Trie
後綴Trie的字符串集合是由指定字符串的後綴子串構成的。好比、完整字符串"minimize"的後綴子串組成的集合S分別以下:
s1=minimize
s2=inimize
s3=nimize
s4=imize
s5=mize
s6=ize
s7=ze
s8=e
而後把這些子串的公共前綴做爲內部結點構成一棵"minimize"的後綴樹,以下圖所示:
節省空間
由於長度爲n的串X的後綴總長度爲n(n+1)/2,顯式存儲X的全部後綴所需空間爲O(n²)。然後綴Trie隱式地表示這些串所需空間爲O(n)。
後綴Trie建立(圖示)
當插入子串時,發現葉子結點中的關鍵字與子串有公共前綴,則須要將該葉子結點分裂。如上圖第3到4步。不然,從新建立一個葉子結點來存放後綴,如上圖第1到2步。
Suffix Trie的子串查詢
若是在後綴樹T中查找子串P,咱們須要這樣的過程:
(1) 從根結點root出發,遍歷全部的根的孩子結點:N1,N2,N3....
(2) 若是全部孩子結點中的關鍵字的第一個字符都和P的第一個字符不匹配,則沒有這個子串,查找結束。
(3) 假如N3結點的關鍵字K3第一個字符與P的相同,則匹配K3和P。
若 K3.length>=P.length 而且K3.subString(0,P.length-1)=P,則匹配成功,不然匹配失敗。
若 K3.length<=P.length 而且K3=P.subString(0, K3.length-1),則將子串P1=P.subString(K3.length, P.length); 即取出P中排除K3以後的子串。而後P1以N3爲根結點繼續重複(1)~ (3)的步驟。直到匹配完P1的全部字符,則匹配成功。不然匹配失敗。
查詢效率:很顯然,在上面的算法中。匹配成功正比如較了P.length次字符。而定位結點的孩子指針,和Trie狀況相似,假如字母表數量爲d。則查詢效率爲O(d*m),實際上,d是固定常數,若是使用Hash表直接定位,則d=1.
所以,後綴樹查詢子串P的時間複雜度爲O(m),其中m爲P的長度。可是構造後綴Trie的時間爲O(dn)。
後綴Trie應用
標準Trie樹只適合前綴匹配和全字匹配,並不適合後綴和子串匹配。然後綴Trie在這方面則很是合適。
參考:
①Michael T. Goodrich Roberto Tamassia Algorithm Design Foundations, Analysis, and Internet Examples
②Heart.X.Raid: http://hxraid.iteye.com/blog/618962
③Heart.X.Raid: http://hxraid.iteye.com/blog/620414