簡與美(1)

最近在做項目的時候經常使用數學,把很多複雜的問題化簡成很簡單的模型,而這使得實現相當美觀,爲了激勵自己繼續鑽研下去,也希望總結一些得失,我打算從今天開始陸續寫一個《簡與美》系列。
 
腦中的數學是抽象的,手中的數學是簡單的。
 
上週做一個分詞器。一個普通的分詞器,對中文和英文進行自動切分,並標註詞性。主要的技術就兩點,詞典的構造和切詞模型的訓練。
 
詞典的構造要基於分詞器對詞典的要求。一般分詞器對詞典主要是查詢操作,有三種查詢操作,第一種是給定一個詞語w,查詢w是否是詞;第二種是給定一個位置,查詢從該位置起始的最長詞;第三種是給定一個位置,查詢從該位置起始的所有詞語。
 
如果是依賴於字符串比較的詞典查詢算法,對於第二、三種查詢,需要多次進行字符串比較,這是很耗費時間的,但是這種詞典的結構一般是比較簡單的。爲了避免字符串比較操作,出現了逐字比較的查詢算法,這種算法只需要遍歷輸入的句子一次,就可以完成三種查詢,不需要進行字符串比較,但是這要構造非常複雜的數據結構,常用的數據結構是trie樹結構。
 
trie樹是一種有限狀態自動機,每個節點代表一個狀態,根據輸入變量的不同,進行狀態轉移。對於中文句子,輸入變量就是每一個漢字,每輸入一個漢字,就會引發一個狀態轉移,可能是從一個狀態到另一個狀態,也可能是一個狀態到它自身的轉移。假設有n種狀態,輸入變量有m種,那麼trie樹的存儲空間就是O(m*n),一般n>50萬,m>5000,空間佔用相當龐大。而且有些時候trie樹的節點分支很少,造成了空間的大量浪費(有效存儲空間過小,而樹結構存儲空間較大)。於是,有研究者提出了用三個線性數組存儲trie樹結構,並在此基礎上進一步改進,提出了用兩個線性數組表示trie樹的方法,這就是雙數組trie樹。
 
雙數組trie樹是兩個整形數組,一個是base[],一個是check[],base數組中每一個元素對應trie樹中的一個節點,他的值做狀態轉移的基值,check值相當於校驗值,用於檢查該狀態是否存在。對於從狀態s到狀態t的一個轉移,必須要滿足如下兩個條件:
1、base[s] + c = t
2、check[t] = s
其中的c是輸入變量。
base[i]和check[i]均爲0時表示該位置爲空,base[i]爲負值時表示該狀態是一個可結束的狀態。兩個數組按照如下方法構造:
對於狀態AB1、AB2、...ABn,狀態A在數組中下表爲i,check[i]=0,令A的base值base[i] = k,k滿足條件:
base[k+B1]=0,check[k+B1]=0,base[k+B2]=0,check[k+B2]=0,...base[k+Bn]=0,check[k+Bn]=0
也就是說,k的值要保證使A的直接子節點B1、B2、...Bn都能放入數組(這些位置都是空的)即可。k的值確定之後,狀態AB1、AB2、...ABn在數組中的下標隨即確定,分別爲k+B1,k+B2,...k+Bn,同時:
check[k+B1]=check[k+B2]=...=check[k+Bn]=i。
數組構造完成之後,要查找一個關鍵碼Ab,只需要判斷check[base[A]+b]是否等於A,如果是,則Ab在trie樹中可以查詢到,否則查詢失敗。
 
是不是很巧妙呢,其實,寫代碼實現出來也不過100多行,實在是太美了,還有更美的呢。
 
待續...
發佈了30 篇原創文章 · 獲贊 1 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章