hanlp中的N最短路徑分詞

2021-09-20 00:22:07 字數 3610 閱讀 3579

n-最短路徑 是中科院分詞工具nlpir進行分詞用到的乙個重要演算法,張華平、劉群老師在**《基於n-最短路徑方法的中文詞語粗分模型》中做了比較詳細的介紹。該演算法演算法基本思想很簡單,就是給定一待處理字串,根據詞典,找出詞典中所有可能的詞,構造出字串的乙個有向無環圖,算出從開始到結束所有路徑中最短的前n條路徑。因為允許相等長度的路徑並列,故最終的結果集合會大於或等於n。

根據演算法思想,當我們拿到乙個字串後,首先構造圖,接著針對圖計算最短路徑。下面以乙個例子「他說的確實在理」進行說明,開始為了能夠簡單說明,首先假設圖上的邊權值均為1。 

先給出對這句話的3-最短路(即路徑最短的前3名, 因為有並列成分, 所以可能候選路徑大於3)徑求解過程圖: 

從節點4開始, 因為4是第乙個出現多個前驅節點的

首先看圖中上方,它是根據乙個已有詞典構造出的有向無環圖。它將字串分為單個的字,每個字用圖中相鄰的兩個結點表示,故對於長度為n的字串,需要n+1個結點。兩節點間若有邊,則表示兩節點間所包含的所有結點構成的詞,如圖中結點2、3、4構成詞「的確」。

圖構造出來後,接下來就要計算最短路徑,n-最短路徑是基於dijkstra演算法的一種簡單擴充套件,它在每個結點處記錄了n個最短路徑值與該結點的前驅,具體過程如上圖中下方列表。table(4)表示位於結點4時的最短路徑情況,表示從結點0到4有兩條路徑,長度為3的路徑前驅為2;長度為4的路徑前驅為3。前驅括號裡面第二個數表示對相同前驅結點的區分,如(4,1)、(4,2)。由列表可知,該字串的3-最短路徑結果集合為{5,5,6,6,7}。

當然,在實際情況中,權值不可能都設為1的,否則隨著字串長度n和最短路徑n的增大,長度相同的路徑數將會急劇增加。為了解決這樣的問題,我們需要通過某種策略為有向圖的邊賦權重,很自然的想法就是邊的權重就是該詞出現的可能性。

nshortpath的基本思想是dijkstra演算法的變種,拿1-最短路來說吧,先dijkstra求一次最短路,然後沿著最短路的路徑走下去,只不過在走到某個節點的時候,檢查到該節點在路徑上的下乙個節點是否還有別的路到它(從prenode查),如果有,就走這些別的路中的沒走過第一條(它們都是最短路上的途徑節點)。然後推廣到n-最短路,n-最短路中prenode有n個,分別對應n-最短路時候的prenode,就這麼簡單。

**再談prenode的準備

需要為每個頂點維護乙個最小堆,最小堆裡儲存的是邊的花費,每條邊的終點是這個頂點。還需要維護到每個頂點的前n個最小路徑的花費:

回憶一下dijkstra求最短路的時候,我們只需記錄乙個最短路的累計花費就行了

這與此處的n-最短路徑顯著不同。

在遍歷圖的時候,與dijkstra最短路徑不同,n-最短路徑從第二個節點開始,需要將當前節點可能到達的邊根據累積第i短長度+該邊的長度之和排序記錄到prenode佇列陣列中,排序由cqueue完成的。

然後從cqueue出隊,這樣路徑長度就是公升序了,按順序更新 weightarray當前節點就行了。

另外cqueue是乙個不同於普通佇列的佇列,它維護了乙個當前指標(下圖的藍色部分),這個藍色指標在求解第i短路徑的時候會用到。

假定看到這裡,演算法已經計算出了正確的prenode佇列,下面討論如何從prenode中找出n最短路徑的確切途經節點集合。

1-最短路徑的求解

整個計算過程維護了乙個路徑棧,對於上圖來說,

1)首先將最後乙個元素壓入棧(本例中是6號結點),什麼時候這個元素彈出棧,什麼時候整個任務結束。

2)對於每個結點的prenode佇列,維護了乙個當前指標,初始狀態都指向prenode佇列中第乙個元素。這個指標是由cqueue維護的,嚴格來講不屬於演算法關心的問題。

3)從右向左依次取出prenode佇列中的當前元素(當前元素出隊)並壓入棧,並將佇列指標重新指向佇列中第乙個元素。如上圖:6號元素prenode是3,3號元素prenode是1,1號元素prenode是0。

4)當第乙個元素壓入棧後,輸出棧內容即為一條佇列。本例中0, 1, 3, 6便是一條最短路徑。

5)將棧中的內容依次彈出,每彈出乙個元素,就將當時壓棧時該元素對應的prenode佇列指標下移一格。如果到了末尾無法下移,則繼續執行第5步(也就是繼續出棧),如果仍然可以移動,則執行第3步。

對於本例,先將「0」彈出棧,在路徑上0的下乙個是1,得出該元素對應的是1號「a」結點的prenode佇列,該佇列的當前指標已經無法下移,因此繼續彈出棧中的「1」 ;同理該元素對應3號「c」結點,因此將3號「c」結點對應的prenode佇列指標下移。由於可以移動,因此將佇列中的2壓入佇列,2號「b」結點的prenode是1,因此再壓入1,依次類推,直到0被壓入,此時又得到了一條最短路徑,那就是0,1,2,3,6。如下圖:

再往下,0、1、2都被彈出棧,3被彈出棧後,由於它對應的6號元素prenode佇列記錄指標仍然可以下移,因此將5壓入堆疊並依次將其prenode入棧,直到0被入棧。此時輸出第3條最短路徑:0, 1, 2, 4, 5, 6。如下圖:

輸出完成後,緊接著又是出棧,此時已經沒有任何棧元素對應的prenode佇列指標可以下移,於是堆疊中的最後乙個元素6也被彈出棧,此時輸出工作完全結束。我們得到了3條最短路徑,分別是:

0, 1, 3, 6,

0, 1, 2, 3, 6,

0, 1, 2, 4, 5, 6,

推廣到n-最短路

n-最短路中prenode有n個,分別對應n-最短路時候的prenode,也就是當前路徑是第n短的時候,當前節點對應的prenode佇列。

在該圖中,觀察黃顏色的路徑長度**,到達1號、2號、3號結點的路徑雖然有多條,但長度只有一種長度,但到達4號「d」結點的路徑長度有兩種,即長度可能是3也可能是4,此時在「最短路」處(index=0)記錄長度為3時的prenode,在「次短路」處(index=1)處記錄長度為4時的prenode,依此類推。

值得注意的是,此時用來記錄prenode的座標已經由前文求「1-最短路徑」時的乙個數(parentnode值)變為2個數(parentnode值以及index值)。

如上圖所示,到達6號「末」結點的次短路徑有兩個parentnode,乙個是index=0中的4號結點,乙個是index=1的5號結點,它們都使得總路徑長度為6。

當n=2時,我們求得了2-最短路徑,路徑長度有兩種,分別長度為5和6,而路徑總共有6條,如下:

最短路徑:

0, 1, 3, 6,

0, 1, 2, 3, 6,

0, 1, 2, 4, 5, 6,

次短路徑

0, 1, 2, 4, 6,

0, 1, 3, 4, 5, 6,

0, 1, 2, 3, 4, 5, 6,

文章**於random-walk的部落格

hanlp中的N最短路徑分詞

n 最短路徑是中科院分詞工具nlpir進行分詞用到的乙個重要演算法,張華平 劉群老師在 基於n 最短路徑方法的中文詞語粗分模型 中做了比較詳細的介紹。該演算法演算法基本思想很簡單,就是給定一待處理字串,根據詞典,找出詞典中所有可能的詞,構造出字串的乙個有向無環圖,算出從開始到結束所有路徑中最短的前n...

ICTCLAS分詞系統研究(五) N最短路徑

ictclas和別的分司系統不一樣的地方就是於 n最短路徑分詞演算法。所謂n最短路徑其實就是最短路徑和最大路徑的折中,保留前n個最優路徑。這樣做的目的就是對這兩種方法取長補短,既能達到乙個比較理解的分詞不達意效果,又能保證分詞不達意速度。在此處,我們中國人的中庸思想被完美體現 在n 最短路徑求解之前...

GIS中的最短路徑

前段時間,在mapx上用vb實現了最短路徑的演算法。具體思路是,先在mapx上建立拓樸關係,將拓樸儲存到資料庫中,在分析路徑的時候從資料庫中載入拓樸關係,然後運用dijkstra演算法找出最短路徑。這裡面可能有兩個難點 1 如何快速建立拓樸關係。這裡面又可細分為如何組織拓樸結構 如何建立拓樸關係。2...