雙陣列trie樹

2021-09-14 01:35:53 字數 3133 閱讀 1841

原文

trie樹的陣列實現原理

trie(retrieval tree)又稱字首樹,可以用來儲存多個字串,並且非常便於查詢。在trie中查詢乙個字串的時間只取決於組成該串的字元數,與樹的節點數無關。因此,它的查詢速度通常比二叉搜尋樹更快。trie的結構很簡單,每條邊表示乙個字元,從根節點到葉節點就可以表示乙個完整的字串。所以,如果用trie表示一組英文單詞,就是一顆26叉數;表示一組自然數,就是一顆10叉樹。直觀上,實現trie很簡單,比如實現英文單詞的trie,使用如下的節點構造樹:

struct node

;

這樣做雖然簡單,但沒有很好的利用記憶體,edges陣列肯定很多都是閒置的,如果使用到更多字元的話,這種浪費會更嚴重。這裡介紹一種基於陣列結構的trie實現方式,不僅節省記憶體,而且查詢速度更快。基於陣列查表的時間複雜度為o(|p|),基於平衡樹的時間複雜度為o(|p|log|σ|),其中,p表示查詢的字串長度,σ表示字元集合。

基於陣列的實現方式,把trie看作乙個dfa,樹的每個節點對應乙個dfa狀態,每條從父節點指向子節點的有向邊對應乙個dfa變換。遍歷從根節點開始,字串的每個字元作為輸入用來確定下乙個狀態,直到葉節點。

三陣列trie

trie可以用三個陣列來表示:

base: 其中的每個元素對應trie上的乙個節點,即dfa的狀態。對於節點s,base[s]是next和check在狀態轉換表中的起始位置。如果base[i]為負值或沒有next轉換,表示該狀態為乙個詞語。

next: 和check搭配使用,提供資料池分配稀疏向量,用於儲存trie狀態轉換表的各行資料。來自各個節點的轉換向量儲存在此陣列中。

check: 與next平行使用,它與next相同位置的元素記錄了next中對應元素的擁有者,即之前的狀態。

所謂trie狀態轉換表,即狀態轉換矩陣,是dfa裡的概念:橫行是狀態轉換向量,比如,狀態s接受n種輸入字元c1,…,cn,即構成狀態s的狀態轉換向量;縱列是各種狀態,即trie的各節點。

對於輸入字元c,從狀態s轉換到t,用三陣列trie可以表示為:

check[base[s]+c] = s

next[base[s]+c] = t

類似下圖: trie tripple

遍歷樹對於給定狀態s和輸入字元c的遍歷演算法表示如下:

t := base[s]+c

if check[t] = s then

next state := next[t]

else

fail

endif

建立樹

當插入乙個狀態轉換,比如,輸入字元c,狀態從s轉換到t,此時,陣列元素next[base[s]+c]]應該是空的,否則,整個占用該陣列元素位置的狀態轉換向量或者狀態s的狀態轉換向量必須要重新遷移(relocate)。實際過程中選擇代價較小的那個。假設遷移狀態s的狀態轉換向量,重新分配的起始位置為b,整個過程很簡單:

relocate(s: 狀態, b: next陣列中新的起始位置)

begin

foreach 狀態s後的每種輸入字元c

begin

check[b+c] := s 標記前件狀態

next[b+c] := next[base[s]+c] 複製原先的狀態資料

check[base[s]+c] := none 釋放原先的狀態資料

endbase[s] := b 完成遷移

end

新位置b的選擇比較關鍵,應該避免遷移過程中再次發生衝突。整個過程如下圖,實線表示遷移前,虛線表示遷移後:

雙陣列trie

三陣列trie的next和check陣列元素之間存在間隙,可以將base和next合併,把base陣列中的表示穿插在next中進行,而next中有值的項直接表示為base的內容,這樣就得到兩個平行的陣列base和check,即雙陣列trie。

對於輸入字元c,從狀態s轉換到t,用雙陣列trie可以表示為:

check[base[s]+c] = s

base[s]+c =t

類似下圖 double

遍歷對於給定狀態s和輸入字元c的遍歷演算法表示如下:

t := base[s] + c;

if check[t] = s then

next state := t

else

fail

endif

建立樹

雙陣列trie的建立類似三陣列trie,但重新遷移方法略有不同:

relocate(s: 狀態, s: base陣列中的起始位置)

begin

foreach 狀態s後的每種輸入字元c

begin

check[b+c] := s 標記前件狀態

base[b+c] := base[base[s}+c] 複製原先的狀態資料

foreach 狀態base[s]+c後的每種輸入字元d

begin

check[base[base[s]+c]+d] := b+c

endcheck[base[s]+c] := none 釋放原先的狀態資料

endbase[s] := b 完成遷移

end

整個過程如下圖:

參考an implementation of double-array trie

雙陣列trie樹

雙陣列trie double arraytrie 是trie樹的乙個簡單而有效的實現,由兩個整數陣列構成,乙個是base,另乙個是check。設陣列下標為i,如果base i check i 均為0,表示該位置為空。如果base i 為負值,表示該狀態為詞語。check i 表示該狀態的前一狀態,t...

雙陣列TRIE樹原理

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!原貼 雙陣列trie樹原理 摘要 本文介紹了一種新的內部 內部排序的內部,也就是在記憶體裡 陣列結構的digital search演算法,叫做雙陣列,結合了陣列訪問的快速和鏈式儲存的壓縮。digital search樹的每一條弧在雙陣列中都可以以o...

Trie樹的雙陣列實現

正文組織 1.什麼是trie樹?2.如何實現乙個trie樹?3.三陣列trie tripple array trie 4.雙陣列trie double array trie 5.字尾壓縮 8.雙輸出池分配 double array pool allocation 9.實現dfa determine ...