在中文分词的实现过程中,词典的设计是相当重要的一步,基于整词二分或者逐字二分的分词算法使用的是比较经典的词典结构
该词典结构分为三级,前两级是索引。
本文解决词典存储时候的哈希表一键多值:
从底层开始实现:
1.首先是词典正文的设计:
存储在List<string>结构中,其索引就是每个词在List<string>中的下标
List<string> WordList = new List<string>(); SqlConnection conn = new SqlConnection(SqlConString); conn.Open(); SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = "select word from WordDictionary"; SqlDataReader sdr = cmd.ExecuteReader(); do { while (sdr.Read()) { WordList.Add(sdr[0].ToString()); } } while (sdr.NextResult());
2.其次是首字哈希表的实现
一键多值的解决思路,将多值进行封装,然后存入哈希表(个人愚见,可能有更好的解决方案)
本次词典的哈希表键值是汉字按照GB2312编码进行换算的结果,哈希函数是:
H(汉字编码)=(汉字编码高字节-176)*94+(汉字编码低字节-161)
按照上图的设计,多值由两个值组成,一个是以该汉字为开头的词的个数,另一个是该词的第一个词语在词典正文中的索引项,封装原则是利用“|”(当然也可以用其他字符),因为两个值都是数字,不会和“|”产生冲突。
实现过程:(在上段代码的基础上实现,建立在遍历WordList的基础上)
Hashtable WordDictHash = new Hashtable(); int i = 0; do {
//获得第一个字的索引值 int FirstWordIndex1 = WordDict.FirstChineseWordIndex(WordList[i]); if (WordDictHash.ContainsKey(FirstWordIndex1)) {
//该词的首字已经在哈希表中,则提取该索引对应的键值 string[] s = WordDictHash[FirstWordIndex1].ToString().Split(spiltchar);
//利用“|”分割符将值分割成两个 int c = Convert.ToInt32(s[0]);
//以该字开头的词的个数加1 c++;
//重新封转并存入哈希表 string v = c.ToString() + "|" + s[1]; WordDictHash[FirstWordIndex1] = v; } else { WordDictHash.Add(FirstWordIndex1, "1"+"|"+i.ToString()); } i++; } while (i < WordList.Count);
测试:
由图信息可知,WordList中有298032个词条,其中以“吖”开头的有三个
因此哈希结束之后,“吖”对应的键值是“3|0”,也就是在WordList中“吖”从0开始,以它为开头的词有3个