雙陣列字典樹 Double Array Trie

2022-07-11 20:21:09 字數 3569 閱讀 7871

參考文獻

1.雙陣列字典樹(datrie)詳解及實現

2.小白詳解trie樹

3.**《基於雙陣列trie樹演算法的字典改進和實現》

dat的基本內容介紹這裡就不展開說了,從trie過來的同學應該比較熟悉,trie對記憶體的消耗比較大,dat正是為了優化該問題而提出。此文重點說一下如何去理解dat的base陣列和check陣列,希望能給諸位些幫助,dat中定義base陣列、check陣列滿足的條件為:

base[s] + c = t 

check[t] = s    

這裡s指轉移前的狀態,c指字元的編碼,t指轉移後的狀態,下面逐個理解這兩個公式表示的邏輯。

1. base[s] + c = t

理解這個式子時,不能單純的從陣列取值上去理解,比如直接將s當成base陣列的下標,因為 s 和 t 都是狀態,而 c 是字元編碼,此時就會疑惑,為啥等式兩邊輸出型別都不一致呢?這到底是怎麼個計算關係?如果有類似的疑惑,那麼可以先摒棄這種的想法。

base陣列維護的是trie樹上節點的資訊,這個公式想表達的意思是:狀態 s (也就是乙個節點,trie樹上每個節點都表示乙個狀態,不理解的可以先了解一下狀態機的概念)接收乙個字元 c 後,就得到狀態 t ,而並不是base陣列中下標為 s 處的取值加上 c值 等於 t 值,所以說不能從僅僅從數值計算上理解這個公式。那麼這個公式是如何用在dat的建立中的呢?我們從如下幾個問題入手,來了解這個公式的作用。

1.1  s、t 具體是什麼意思?

s、t 表示dat上的一種狀態、base陣列中的元素,實際上就是trie上的乙個個節點,這個節點上包含很多資訊,建立過trie樹的同學知道,trie樹節點上一般包含:屬性值value(可以用來記錄詞性)、葉子節點標記flag(是否為詞語的未字元)、子節點陣列(用來儲存子節點的資訊)等等

1.2  base陣列中儲存的是什麼?

base陣列維護的是各個狀態的資訊,即陣列中儲存的是各節點的資訊,但是具體內容與1.1節中所說的trie節點資訊不一致,以參考文獻1中實現為例,每個狀態下包含的資訊包括

transferratio:計算子節點在base陣列中下標時的轉移基數,為了解決節點儲存位置衝突而引入的,初始值為0

isleaf:節點是否為詞語的葉子節點。該內容可選,也可以用其它方式表示葉子節點

label:節點儲存的字元,可以理解為該節點是通過插入哪個字元得到的。該內容可選,也可以不要

value:如果該節點為葉子節點,那麼其對應的詞語在詞典中序號。該內容為可選,也可以不要

1.3  base陣列的下標表示什麼意思

base陣列的下標是基於字元的編碼做加減運算得到的數值。參照1.2節中的例子,建立dat儲存詞語「中華」,先建立乙個base陣列,

trienode base[10]     //假設儲存10個節點

令根節點root = new trienode ,很自然的將根節點root存入base[0]。令 root. transferratio=1 (這裡設為1,也可以設個其他值,初始值隨便,保證base陣列不溢位即可)

接著插入字元「中」,假如採用unicode編碼,那麼「中」的碼值為20013,那麼儲存 字元「中」的節點在base陣列中的下標就為

0 + base[0].transferratio + unicode("中")=0+1+20013=20014

令 base[20014].transferratio=1    (這裡設為1主要是為了和初始時的0區分開,表示base[20014]這個位置已經有節點佔據了)

然後插入字元「華」,unicode('華')=21326,因為是節點「中」接收字元「華」,儲存 字元「華」的節點在base陣列中的下標就為

20014+ base[20014].transferratio + unicode('華')=20014+0+21326=41340,

令base[41340].transferratio=1  ,原因同上。

1.4  c值怎麼計算

c值得計算除了1.3中說的計算字元得unicode值,你還可以計算字元hash值得到,只要保證每個字元(中文、英文、日文等等文字的字元)有乙個唯一且確定得編碼值即可。

通過以上幾個問題的說明可知,dat中每個狀態的下標是唯一的(解決位置衝突之後),可以用base陣列的下標表示狀態,通過索引base陣列的下標即可得到各個狀態的資訊。此時,我們再來從數值計算的角度來理解這個公式,即狀態 s 的下標(還要加上偏移transferratio)加上字元c的編碼值,等於狀態 t (由狀態s 接收字元c 得到)的下標。

2. check[t] = s

理解這個等式,先要從dat的查詢邏輯說起。在trie中,我們是怎麼判斷詞語存在的?從根節點開始,依次查詢詞語中的每個字元,若各個字元均存在於當前節點的子節點中,則表明該詞語存在。如果在dat上也按照這個邏輯來判斷詞語是否存在,則查詢過程是這樣的:還是以1.3節為例,查詢詞語 「中華」 是否存在。從根節點開始,首先查詢 「中」字,

0 + base[0].transferratio + unicode("中")=0+1+20013=20014

若base[20014].transferratio ≠ 0 ,則表明字元「中」存在。(判斷base陣列中乙個位置上是否有資料可以採用很多方式,這裡採用參考文獻1中的實現方式,即判斷trienode.transferratio是否非0)

接著查詢字元「華」,

20014+ base[20014].transferratio + unicode('華')=20014+0+21326=41340

若base[20014].transferratio ≠ 0,則表明「華」存在。那麼這個邏輯在dat上是否可靠呢?答案是不可靠,因為在dat上節點轉移是通過在base陣列上索引字元unicode碼值進行的,這就會存在以下的情況

unicode(a)  ≠  unicode(b)

unicode(a)+unicode(c) = unicode(b)+unicode(d)

其中 a、b、c、d指unicode編碼規範中收錄的某個字元,此種情況下的查詢邏輯就會出錯,所以在dat中引入了check陣列,在check陣列中儲存的是當前狀態的父狀態(即當前節點的父節點),還是以1.3節中詞語「中華」為例,以base陣列的下標表示狀態,字元「中」所在節點的父節點為根節點,所以check[20014]=0;字元「華」所在節點的父節點下標為20014,即check[41340]=20014,這樣可以確定當前節點的父節點是哪乙個,從而解決unicode(a)+unicode(c) = unicode(b)+unicode(d) 帶來的問題。

以上介紹的內容是基於參考文獻1中的簡單實現來說明的,實際上可以基於dat的基本邏輯做很多種實現。

雙陣列trie樹

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

雙陣列trie樹

原文 trie樹的陣列實現原理 trie retrieval tree 又稱字首樹,可以用來儲存多個字串,並且非常便於查詢。在trie中查詢乙個字串的時間只取決於組成該串的字元數,與樹的節點數無關。因此,它的查詢速度通常比二叉搜尋樹更快。trie的結構很簡單,每條邊表示乙個字元,從根節點到葉節點就可...

雙陣列TRIE樹原理

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