Trie樹的學習

所寫內容,是對自己所學知識的一個記錄罷了。

1.簡介

最近在做中國人名識別的時候,看到一篇文章是基於角色的人名識別,而角色字典中有2個角色是用雙數組Tire樹來建立的,當時沒有看懂,於是來先學習Trie樹。

Trie樹,又稱字典樹,單詞查找樹或者前綴樹等,是一種快速 檢索的多叉樹結構。比如,英文字母的字典樹是一個20叉樹,數字的字典樹是一個10叉樹。

字典樹(Trie)可以保存一些字符串-->值的對應關係。這和java中的HashMap的功能相同,都是KEY-VALUE的映射,只不過Trie樹的KEY是字符串而已(當然不僅限於字符串)。如果我們有and,as,at,cn,com這些關鍵詞,我們可以構建如下的Trie樹。


由上圖,我們可以歸爲Trie樹的基本性質爲:

(1)根節點不包含字符,除根節點外每個節點只包含一個字符

(2)從根節點到某一個節點,路徑上經過的字符鏈接起來,爲該節點對應的字符串

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


2.複雜度

Trie的插入(Insert)、刪除( Delete)和查找(Find)都非常簡單,用一個一重循環即可,即第i 次循環找到前i 個字母所對應的子樹,然後進行相應的操作。

(1)插入過程

對於一個單詞,從根開始,沿着單詞的各個字母所對應的樹中的節點分支向下走,直到單詞遍歷完,將最後的節

點標記爲紅色,表示該單詞已插入Trie樹。

(2)查詢過程

同樣的,從根開始按照單詞的字母順序遍歷Trie樹,一旦發現某個節點標記不能存在或者遍歷完成而最優的節點

未標記爲紅色,則表示該單詞不存在;反之,則表示該單詞存在。

Trie樹的強大之處在於它的時間複雜度,它的插入和查詢時間複雜度都爲 O(N) ,其中N爲KEY的長度,與 Trie 中保存了多少個元素無關。Hash 表號稱是 O(1) 的,但在計算 hash 的時候就肯定會是 O(N) ,而且還有碰撞之類的問題;Trie 的缺點是空間消耗很高。例如,英文字母的Trie樹的空間複雜度要爲26^N。實現這棵字母樹,我們用最常見的數組保存(靜態開闢內存)即可,當然也可以開動態的指針類型(動態開闢內存)。

Trie樹的一些特性

(1)根節點不包含字符,除根節點外每一個節點都只包含一個字符。

(2)從根節點到某一節點,路徑上經過的字符連接起來,爲該節點對應的字符串。

(3)每個節點的所有子節點包含的字符都不相同。

(4)如果字符的種數爲N,則每個節點的出度爲N,這也是空間換時間的體現,浪費了很多的空間。

(5)插入查找的複雜度爲O(N),N爲字符串長度。


3.應用

Trie樹是一種樹形結構,是一種哈希樹的變種。所以二者有着千絲萬縷的關係。Trie的核心思想是犧牲空間換取時間的效率。利用字符串的公共前綴來降低查詢時間的開銷以達到提高效率的目的。

(1)詞頻統計

典型的應用是用於統計和排序大量的字符串(但不僅限於字符串),所以經常被搜索引擎用於文本詞頻統計。但是Hash或者堆也可以解決這個問題,那爲什麼還要用Trie樹呢?因爲當內存有限的時候,我們可以用Trie樹來壓縮空間,因爲公共前綴都是用一個節點保存的。最大限度的減少無謂的字符串比較,查詢效率比哈希表要高。

(2)前綴匹配

這個就是我在開始提到的人名識別的角色的建立用的。如果想深入瞭解,可參考http://www.hankcs.com/nlp/segment/ictclas-the-hmm-name-recognition.html。好了,想要大家瞭解一下還有這麼個應用而已^_^。繼續往下看,還拿上面的圖來說,如果我想獲得所有以“a”開頭的字符串,從圖中可以名下的看到是and,as,at。那麼,如果不用Trie樹呢?我們最容易想到的就是對字符串集從頭到尾進行搜索  ,看每個字符串是否爲字符串集中的前綴子串,其複雜度爲O(N^2)。這個複雜度可是算很高的了。可能還會有人想到用hash,我們使用hash存下所有字符串的所有前綴子串。建立存有子串的hash複雜度爲O(N*len)。查詢的複雜度爲O(N)。那使用Trie樹的有點在哪呢?如果我們要查詢如字符串"abcd"是否爲某個字符串的前綴時,顯然以"b","c","d"等等不是以"a"開頭的字符串就不用查找了,這樣迅速縮小了查找範圍且提高了查找的針對性。所以建立Trie樹的複雜度爲O(N*len),而建立+查詢在Trie樹是可以同時執行的,建立的過程也就是查詢的過程,而hash是不能實現這個功能的所以總的複雜度爲O(N*len),實際查詢的複雜度只是O(len)。

(3)排序

Trie是一棵多叉樹,只要先序遍歷整棵樹(先序是樹的一個基本遍歷,後面也記錄一下,省的忘了 ^_^),輸出相應的字符串便是按字典序排序的結果。例如@ 給你N 個互不相同的僅由一個單詞構成的英文名,讓你將它們按字典序從小到大排序輸出。

下面以二叉樹爲例子,講述一下先序,中序及後序遍歷。一般約定遍歷時左節點優於右節點。

前序:先遍歷根節點,在處理左右節點。即:根-->左-->右

中序:先遍歷左節點,然後處理根節點,左右處理右節點。即:-->-->右

後序:先遍歷左右節點,再處理根節點。即:左-->右-->

(4)作爲其他數據結構和算法的輔助結構

例如:後綴樹(這個在前面提到的人名識別也有應用),AC自動機等


還在繼續學習中。。。先記錄到這。。。



4.參考資料

(1)http://dongxicheng.org/structure/trietree/

(2)http://blog.csdn.net/hackbuteer1/article/details/7964147



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章