在以前的兩篇博文中文分詞算法 之 基於詞典的正向最大匹配算法和中文分詞算法 之 基於詞典的逆向最大匹配算法中,咱們對分詞實現和詞典實現都作了優化,本文對詞典實現作進一步優化,並和以前的多個實現作一個對比,使用的詞典下載地址,使用的測試文本下載地址。java
優化TrieV3的關鍵在於把虛擬根節點(/)的子節點(詞表首字母)提高爲多個相互獨立的根節點,並對這些根節點創建索引。優化的依據是根節點(詞表首字母)的數量龐大,索引查找的速度遠遠超過二分查找。git
下面看看進一步優化後的TrieV4和以前的TrieV3的對比:github
/** * 獲取字符對應的根節點 * 若是節點不存在 * 則增長根節點後返回新增的節點 * @param character 字符 * @return 字符對應的根節點 */ private TrieNode getRootNodeIfNotExistThenCreate(char character){ TrieNode trieNode = getRootNode(character); if(trieNode == null){ trieNode = new TrieNode(character); addRootNode(trieNode); } return trieNode; } /** * 新增一個根節點 * @param rootNode 根節點 */ private void addRootNode(TrieNode rootNode){ //計算節點的存儲索引 int index = rootNode.getCharacter()%INDEX_LENGTH; //檢查索引是否和其餘節點衝突 TrieNode existTrieNode = ROOT_NODES_INDEX[index]; if(existTrieNode != null){ //有衝突,將衝突節點附加到當前節點以後 rootNode.setSibling(existTrieNode); } //新增的節點老是在最前 ROOT_NODES_INDEX[index] = rootNode; } /** * 獲取字符對應的根節點 * 若是不存在,則返回NULL * @param character 字符 * @return 字符對應的根節點 */ private TrieNode getRootNode(char character){ //計算節點的存儲索引 int index = character%INDEX_LENGTH; TrieNode trieNode = ROOT_NODES_INDEX[index]; while(trieNode != null && character != trieNode.getCharacter()){ //若是節點和其餘節點衝突,則須要鏈式查找 trieNode = trieNode.getSibling(); } return trieNode; }
不一樣的字符可能會映射到同一個數組索引(映射衝突),因此須要給TrieNode增長一個引用sibling,當衝突發生的時候,可利用該引用將多個衝突元素連接起來,這樣,在一個數組索引中就能存儲多個TrieNode。若是衝突大量發生,不但會浪費已經分配的數組空間,並且會引發查找性能的降低,好在這裏根節點的每一個字符都不同,衝突發生的狀況很是少。咱們看看詞數目爲427451的詞典文件的衝突狀況:算法
衝突次數爲:1 的元素個數:2746 衝突次數爲:2 的元素個數:1 衝突次數:2748 總槽數:12000 用槽數:9024 使用率:75.2% 剩槽數:2976
將詞典文件和測試文本解壓到當前目錄下,使用下面的命令進行測試,須要注意的是,這裏的-Xmx參數指定的值是相應的詞典實現所須要的最小的堆空間,若是再小就沒法完成分詞:數組
nohup java -Ddic.class=org.apdplat.word.dictionary.impl.TrieV4 -Xmx40m -cp target/word-1.0.jar org.apdplat.word.SegFile & nohup java -Ddic.class=org.apdplat.word.dictionary.impl.TrieV3 -Xmx40m -cp target/word-1.0.jar org.apdplat.word.SegFile & nohup java -Ddic.class=org.apdplat.word.dictionary.impl.TrieV2 -Xmx40m -cp target/word-1.0.jar org.apdplat.word.SegFile & nohup java -Ddic.class=org.apdplat.word.dictionary.impl.TrieV1 -Xmx120m -cp target/word-1.0.jar org.apdplat.word.SegFile & nohup java -Ddic.class=org.apdplat.word.dictionary.impl.Trie -Xmx200m -cp target/word-1.0.jar org.apdplat.word.SegFile & nohup java -Ddic.class=org.apdplat.word.dictionary.impl.HashSet -Xmx50m -cp target/word-1.0.jar org.apdplat.word.SegFile &
測試結果以下:性能
參考資料:優化
一、中文分詞十年回顧spa
二、中文信息處理中的分詞問題code