雙陣列Trie樹高效構建有向無環圖

超人汪小建發表於2018-07-19

圖是很常見的一種結構了,不管是資料結構演算法中的各種圖結構,還是機器學習中的概率圖。圖主要是由若干頂點及連線兩頂點的邊所構成的圖形,通過它可以用來描述某些事物之間的某種特定關係。

有向無環圖

有向無環圖,即 Directed Acyclic Graph,屬於有向圖,圖結構中不存在環,可用來表示事件之間依賴關係。

雙陣列Trie樹高效構建有向無環圖

Trie樹

Trie 是一種搜尋樹,它的 key 都為字串,通過 key 可以找到 value。能做到高效查詢和插入,時間複雜度為O(k),缺點是耗記憶體。它的核心思想就是減少沒必要的字元比較,使查詢高效率,即用空間換時間,再利用共同字首來提高查詢效率。

Trie 樹的根節點不包含字元,根節點到某節點的路徑連起來的字串為該節點對應的字串,每個節點只包含一個字元,此外,任意節點的所有子節點的字元都不相同。

比如如下,將五個詞語新增到 Trie 樹中,最後的結構如圖所示。

TrieTree tree = new TrieTree();
tree.put("美利堅");
tree.put("美麗");
tree.put("金幣");
tree.put("金子");
tree.put("帝王");
複製程式碼

雙陣列Trie樹高效構建有向無環圖

雙陣列Trie

Trie 樹的實現可以有多種方法,主要的差異是儲存結構的不同,不同的儲存結構將導致佔用空間不同。常見有定長陣列方式、變長列表等。

雙陣列Trie樹高效構建有向無環圖

雙陣列Trie樹高效構建有向無環圖

而其中有一種方式能讓效能和佔用空間都達到較好水平,這就是雙陣列方式,即雙陣列 Trie 樹。雙陣列意思就是由兩個陣列來實現儲存,分別為 base 和 check 陣列,它們時兩個互相平行的陣列。

base 陣列和 check 陣列記錄了所有轉換狀態,假如接收了一個字元 c ,要從狀態 s 移動到 t 的轉移,則對應在雙陣列中的條件是:

check[base[s] + c] = s
base[s] + c = t
複製程式碼

根據現有詞典將所有狀態都建立起來後,後面查詢時則直接根據字與字之間的狀態轉換並根據 check 陣列的值即可以判斷是否已經完成單詞的搜尋,其中 base 陣列主要作用是可以用來判斷是否存在某些字到字的狀態轉換,而 check 陣列則主要用來判斷是否是一個完整詞語。

雙陣列Trie樹高效構建有向無環圖

有向無環圖作用

比如對於這麼個任務:存在一個大詞典,要根據該詞典找出一段文章包含的所有可能的詞,這樣就能從頭到尾構建若干條路徑,而且每個詞對應的邊都可能有不同的權重值,而最終將該段文章怎樣分詞取決於哪個路徑的值最小或者哪個路徑走到終點的概率最大。

為了構建這個有向無環圖,會涉及到遍歷大量資料集的問題,這正是引入雙陣列 Trie 樹的原因,將耗時的搜尋交給雙陣列 Trie 樹,只需要從頭到尾暴力匹配即能完成有向無環圖的建立了。

繼續優化?

引入 AC 自動機應該還能繼續優化。

github

https://github.com/sea-boat/TextAnalyzer/blob/master/src/main/java/com/seaboat/text/analyzer/data/structure/DAGModel.java

-------------推薦閱讀------------

我的開源專案彙總(機器&深度學習、NLP、網路IO、AIML、mysql協議、chatbot)

為什麼寫《Tomcat核心設計剖析》

我的2017文章彙總——機器學習篇

我的2017文章彙總——Java及中介軟體

我的2017文章彙總——深度學習篇

我的2017文章彙總——JDK原始碼篇

我的2017文章彙總——自然語言處理篇

我的2017文章彙總——Java併發篇


跟我交流,向我提問:

雙陣列Trie樹高效構建有向無環圖

歡迎關注:

雙陣列Trie樹高效構建有向無環圖

相關文章