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

2021-04-07 06:02:56 字數 4213 閱讀 5971

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

在n-最短路徑求解之前,ictclas首先通過二叉分詞圖表(鄰接表,如下圖一所示)表示出了每個片語之間的耦合關係,每乙個節點都表示分詞圖表中的一條邊,它的行值代表邊的起點(前驅),它的列值代表邊的終點(後驅),這一點務必弄清楚。可以通過圖

一、圖二相結合對照來理解。通過計算片語之間的耦合關係,來最終確定初次的分詞路徑。我們都知道dijkstra演算法是求源點到某一點的最短路徑,也就是最優的那一條,在此處的n-最短路徑指的是找出前n條最優的路徑(實際上在freeictclas的源**當中n是等於1的,即nvaluekind==1)。按照dijkstra的表示方法把二叉分詞圖表轉化成圖二的表示形式,就能比較清楚地看出來,求解的過程實際就是求源點0到終於12的最短路徑,和純粹的dijkstra演算法不同的地方是在此處需要記錄每個節點的n個前驅,dijkstra當中記錄乙個即可。

圖一圖二

在求解過程中,源程式通過二維陣列m_pparent[i][j]、m_pweight[m][n]來記錄每個節點的n個前驅和每個前驅和權重,而求解最短路徑權重時借用了乙個佇列來實現排序,資料結構如下圖三所示:        

圖四在源程式中,n最短路徑是在cnshortpath類裡裡面實現的。

bool

csegment::bisegment(

char

*ssentence, 

double

d**oothingpara, cdictionary 

&dictcore, cdictionary 

&dictbinary, unsigned 

intnresultcount)

...

對源**進行解析,以「他說的確實在理」為例項:

//進行n-最短路徑的求解,找出每乙個節點的前驅計算前驅的權值(從源點到該前驅節點)

intcnshortpath::shortpath()

...else

//該條邊的起點是0,即該起點沒有父結點,是分詞的源點

...}

//end for

pedgelist

=pedgelist

->

next;}//

end while

//now get the result queue which sort as weight.

//set the current node information

for(i=0

;i<

m_nvaluekind;i++)

...//

memset((void *),(int),sizeof(element_type)*);

//init the weighti=

0;       

//設定當前節點的n個前驅節點的最短路徑的權值 

//以"他說的確實在理"為例

//m_pweight[0][0]=3.846

//m_pweight[1][0]=6.025

//m_pweight[2][0]=10.208

//m_pweight[3][0]=15.063

//m_pweight[4][0]=16.190

//m_pweight[5][0]=16.184

//m_pweight[6][0]=28.331

//m_pweight[7][0]=28.331

//m_pweight[8][0]=28.923

//m_pweight[9][0]=28.923

//m_pweight[10][0]=36.416

//m_pweight[11][0]= 39.889

while

(i<

m_nvaluekind

&&quework.pop(

&nprenode,

&nindex,

&eweight)

!=-1

)...

//m_pparent[0][0]=(0,0,0)

//m_pparent[1][0]=(1,0,0)

//m_pparent[2][0]=(2,0,0)

//m_pparent[3][0]=(2,0,0)

//m_pparent[4][0]=(3,0,0)

//m_pparent[5][0]=(3,0,0)

//m_pparent[6][0]=(4,0,0)

//m_pparent[7][0]=(4,0,0)

//m_pparent[8][0]=(6,0,0)

//m_pparent[9][0]=(6,0,0)

//m_pparent[10][0]=(9,0,0)

//m_pparent[11][0]=(11,0,0)

m_pparent[ncurnode-1

][i].push(nprenode,nindex);}}

//end for

return1;

}

經過對每個節點的前驅求解後,得到前驅的最短路徑權值和它的父節點,記錄如下圖四所示:

圖四然後通過佇列(其實更象乙個棧)來求出二叉分詞路徑: 

//bbest=true: only get one best result and ignore others

//added in 2002-1-24

void

cnshortpath::getpaths(unsigned 

intnnode,unsigned 

intnindex,

int**

nresult,

bool

bbest)

...if

(ncurnode

>0)

queresult.push(ncurnode,ncurindex);}//

當到0節點時,也就意為著形成了一條最短路徑

if(ncurnode==0

)...

nresult[m_nresultcount][nresultindex]=-1

;//

set the end

m_nresultcount+=1

;//

the number of result add by 1

if(m_nresultcount

>=

max_segment_num)

//only need 10 result

return

;nresultindex=0

;nresult[m_nresultcount][nresultindex]=-1

;//

init the result 

if(bbest)

//return the best result, ignore others

return;}

//首先判斷棧頂元素是否有下乙個前驅,如果沒有則刪除棧頂元素直到有下乙個前驅的元素出現

queresult.pop(

&ncurnode,

&ncurindex,0,

false

,true

);//

read the top node

while

(queresult.isempty()

==false

&&(m_pparent[ncurnode-1

][ncurindex].issingle()

||m_pparent[ncurnode-1

][ncurindex].isempty(

true

)))...

//如果找到了有下乙個前驅的節點,則它的前驅壓入棧中,重新迴圈直到把源點也壓入

if(queresult.isempty()

==false

&&m_pparent[ncurnode-1

][ncurindex].isempty(

true)==

false

)...}}

最終得到最短路麼(0,1,2,3,6,9,11,12),裡面的數值分別對應研究(四)中圖四的下標,到此分詞的第一大步就結束了,並形成最終結果:始##始/他/說/的/確實/在/理/末##末

ICTCLAS分詞系統研究(三) 原子切分

ictclas分詞的第一步就是原子分詞。但在進行原子切分之前,首先要進行斷句處理。所謂斷句,就是根據分隔符 回車換行符等語句的分隔標誌,把源字串分隔成多個稍微簡單一點的短句,再進行分詞處理,最後再把各個分詞結果合起來,形成最終的分詞結果。分成短句之後,即可進行原子分詞,所謂原子,是指該短句中不可分割...

DOS系統研究

這裡說的特指ms dos,一款由微軟從seattle computer products購買來的針對16位8086 8088系列處理器的作業系統。它隨著由16位的80x86處理器的桌面電腦的普及而成為曾經的主流作業系統,但是當更先進的處理器在桌面電腦中流行後,它的主流地位也讓位於其他更成熟的作業系統...

ACARS系統研究

1 概述 acars aircraftcommunication addressing reporting systems 飛機通訊定址報告系統,美國arinc公司開發,採用迴圈冗餘校驗碼 crc 進行校驗。航空器與地面站之間通過無線電或衛星傳輸短訊息 報文 的數字資料鏈系統。具有傳輸速度快 抗干擾...