1. 程式人生 > >Trie(字首樹/字典樹)及其應用

Trie(字首樹/字典樹)及其應用

Trie,又經常叫字首樹,字典樹等等。它有很多變種,如字尾樹,Radix Tree/Trie,PATRICIA tree,以及bitwise版本的crit-bit tree。當然很多名字的意義其實有交叉。

 

定義

在電腦科學中,trie,又稱字首樹或字典樹,是一種有序樹,用於儲存關聯陣列,其中的鍵通常是字串。與二叉查詢樹不同,鍵不是直接儲存在節點中,而是由節點在樹中的位置決定。一個節點的所有子孫都有相同的字首,也就是這個節點對應的字串,而根節點對應空字串。一般情況下,不是所有的節點都有對應的值,只有葉子節點和部分內部節點所對應的鍵才有相關的值。

trie中的鍵通常是字串,但也可以是其它的結構。trie的演算法可以很容易地修改為處理其它結構的有序序列,比如一串數字或者形狀的排列。比如,bitwise trie中的鍵是一串位元,可以用於表示整數或者記憶體地址

 

基本性質

1,根節點不包含字元,除根節點意外每個節點只包含一個字元。

2,從根節點到某一個節點,路徑上經過的字元連線起來,為該節點對應的字串。

3,每個節點的所有子節點包含的字串不相同。

 

優點

可以最大限度地減少無謂的字串比較,故可以用於詞頻統計和大量字串排序。

  跟雜湊表比較:

    1,最壞情況時間複雜度比hash表好

    2,沒有衝突,除非一個key對應多個值(除key外的其他資訊)

    3,自帶排序功能(類似Radix Sort),中序遍歷trie可以得到排序。

缺點

1,雖然不同單詞共享字首,但其實trie是一個以空間換時間的演算法。其每一個字元都可能包含至多字符集大小數目的指標(不包含衛星資料)。

每個結點的子樹的根節點的組織方式有幾種。1>如果預設包含所有字符集,則查詢速度快但浪費空間(特別是靠近樹底部葉子)。2>如果用連結法(如左兒子右兄弟),則節省空間但查詢需順序(部分)遍歷連結串列。3>alphabet reduction: 減少字元寬度以減少字母集個數。,4>對字符集使用bitmap,再配合連結法。

2,如果資料儲存在外部儲存器等較慢位置,Trie會較hash速度慢(hash訪問O(1)次外存,Trie訪問O(樹高))。

3,長的浮點數等會讓鏈變得很長。可用bitwise trie改進。

 

bit-wise Trie

類似於普通的Trie,但是字符集為一個bit位,所以孩子也只有兩個。

可用於地址分配,路由管理等。

雖然是按bit位儲存和判斷,但因為cache-local和可高度並行,所以效能很高。跟紅黑樹比,紅黑樹雖然紙面效能更高,但是因為cache不友好和序列執行多,瓶頸在儲存訪問延遲而不是CPU速度。

 

壓縮Trie

壓縮分支條件:

1,Trie基本不變

2,只是查詢

3,key跟結點的特定資料無關

4,分支很稀疏

若允許新增和刪除,就可能需要分裂和合並結點。此時可能需要對壓縮率和更新(裂,並)頻率進行折中。

 

外存Trie

某些變種如字尾樹適合儲存在外部,另外還有B-trie等。

 

應用場景

(1) 字串檢索
事先將已知的一些字串(字典)的有關資訊儲存到trie樹裡,查詢另外一些未知字串是否出現過或者出現頻率。
舉例:
1,給出N 個單片語成的熟詞表,以及一篇全用小寫英文書寫的文章,請你按最早出現的順序寫出所有不在熟詞表中的生詞。
2,給出一個詞典,其中的單詞為不良單詞。單詞均為小寫字母。再給出一段文字,文字的每一行也由小寫字母構成。判斷文字中是否含有任何不良單詞。例如,若rob是不良單詞,那麼文字problem含有不良單詞。

3,1000萬字符串,其中有些是重複的,需要把重複的全部去掉,保留沒有重複的字串。

 

(2)文字預測、自動完成,see also,拼寫檢查

 

(3)詞頻統計

1,有一個1G大小的一個檔案,裡面每一行是一個詞,詞的大小不超過16位元組,記憶體限制大小是1M。返回頻數最高的100個詞。

2,一個文字檔案,大約有一萬行,每行一個詞,要求統計出其中最頻繁出現的前10個詞,請給出思想,給出時間複雜度分析。

3,尋找熱門查詢:搜尋引擎會通過日誌檔案把使用者每次檢索使用的所有檢索串都記錄下來,每個查詢串的長度為1-255位元組。假設目前有一千萬個記錄,這些查詢串的重複度比較高,雖然總數是1千萬,但是如果去除重複,不超過3百萬個。一個查詢串的重複度越高,說明查詢它的使用者越多,也就越熱門。請你統計最熱門的10個查詢串,要求使用的記憶體不能超過1G。
(1) 請描述你解決這個問題的思路;
(2) 請給出主要的處理流程,演算法,以及演算法的複雜度。

==》若無記憶體限制:Trie + “k-大/小根堆”(k為要找到的數目)。

否則,先hash分段再對每一個段用hash(另一個hash函式)統計詞頻,再要麼利用歸併排序的某些特性(如partial_sort),要麼利用某使用外存的方法。參考

  “海量資料處理之歸併、堆排、前K方法的應用:一道面試題” http://www.dataguru.cn/thread-485388-1-1.html

  “演算法面試題之統計詞頻前k大” http://blog.csdn.net/u011077606/article/details/42640867

   演算法導論筆記——第九章 中位數和順序統計量 

 

(4)排序

Trie樹是一棵多叉樹,只要先序遍歷整棵樹,輸出相應的字串便是按字典序排序的結果。
比如給你N 個互不相同的僅由一個單詞構成的英文名,讓你將它們按字典序從小到大排序輸出。

 

(5)字串最長公共字首
Trie樹利用多個字串的公共字首來節省儲存空間,當我們把大量字串儲存到一棵trie樹上時,我們可以快速得到某些字串的公共字首。
舉例:
給出N 個小寫英文字母串,以及Q 個詢問,即詢問某兩個串的最長公共字首的長度是多少?
解決方案:首先對所有的串建立其對應的字母樹。此時發現,對於兩個串的最長公共字首的長度即它們所在結點的公共祖先個數,於是,問題就轉化為了離線(Offline)的最近公共祖先(Least Common Ancestor,簡稱LCA)問題。
而最近公共祖先問題同樣是一個經典問題,可以用下面幾種方法:
1. 利用並查集(Disjoint Set),可以採用採用經典的Tarjan 演算法;
2. 求出字母樹的尤拉序列(Euler Sequence )後,就可以轉為經典的最小值查詢(Range Minimum Query,簡稱RMQ)問題了;

 

(6)字串搜尋的字首匹配
trie樹常用於搜尋提示。如當輸入一個網址,可以自動搜尋出可能的選擇。當沒有完全匹配的搜尋結果,可以返回字首最相似的可能。
Trie樹檢索的時間複雜度可以做到n,n是要檢索單詞的長度,
如果使用暴力檢索,需要指數級O(n2)的時間複雜度。

 

(7) 作為其他資料結構和演算法的輔助結構
如字尾樹,AC自動機等

字尾樹可以用於全文搜尋

 

轉一篇關於幾種Trie速度比較的文章:http://www.hankcs.com/nlp/performance-comparison-of-several-trie-tree.html

Trie樹和其它資料結構的比較 http://www.raychase.net/1783

 

參考:

[1] 維基百科:Trie, https://en.wikipedia.org/wiki/Trie

[2] LeetCode字典樹(Trie)總結, http://www.jianshu.com/p/bbfe4874f66f

[3] 字典樹(Trie樹)的實現及應用, http://www.cnblogs.com/binyue/p/3771040.html#undefined

[4] 6天通吃樹結構—— 第五天 Trie樹, http://www.cnblogs.com/huangxincheng/archive/2012/11/25/2788268.html