简单的英文变位词聚类算法

有时,简单的算法也有其实用的意义,由于之前公司内部搜索引擎优化的需要,我根据《编程珠玑》中查找英文单词变位词的算法,来实现搜索纠错的功能。

在搜索时,有时记不住单词,会出现拼写错误的情况,例如,搜索“height”时手误,搜索了“heigth”,那么我们要在搜索不到的情况下,给他变位词作为提示(注:因为公司内部搜索,该算法已经够用,真正的搜索引擎应该是采用更高效的算法,请有经验的前辈赐教)。

算法分三步:①对单词签名; ②根据签名的字典序排序; ③根据排序结果挤压,使变位词聚合在一起;

a) 快速单词签名算法(当前仅使用于英文单词,如果包含其他字符,需做拓展):

鉴于英文字母可枚举且数量只有26个,故这里采用变形的基数排序算法,以实现快速签名:

Step 1: 定义一个26位的 int[] 数组,数组从0~25分别表示:A,B,C,D …… X,Y,Z (如图1),初始化全部为0:

A

B

C

D

E

F

G

H

I

J

K

L

M

N

O

P

G

R

S

T

U

V

W

X

Y

Z

 

 

 

 

 

 

 

(图1)

Step 2: 将英文字母转换统一(大小写统一),如 Jary → jary,再使用如下公式:存入下标为x-97的位置,例如 a的ascii码为97,则它对应存入byte[]数组中的97-97=0的位置,即该位置自增1;以此类推。

Stpe 3: 给单词签名,从0到25扫描数组,例如 what → ahtw, wath → ahtw, system → ems2ty ;

这样我们就可以只通过一次扫描来获取一个单词的签名,代码如下:

 1 public static string SignWord(string word) 
 2 {
 3     int[] dict = new int[26];
 4 
 5     var array = word.ToLower().ToArray();
 6     foreach(var a in array) {
 7         dict[a - 97]++;
 8     }
 9     StringBuilder sb = new StringBuilder();
10     for (var i = 0; i < 26; i++) {
11         if (dict[i] != 0) {
12             var t = dict[i].ToString().Equals("1") ? "": dict[i].ToString();
13             sb.Append((char)(i + 97) + t);
14         }
15     }
16     return sb.ToString();
17 }

b) 相同签名的单词的挤压,例如,whatwath有相同的签名,则放到一起,我们可以根据签名的字典排序,但是,使用C#提供的Dictnary可以快速排序加压,代码如下:

 1 public static Dictionary < string,List < string >> SqueezeList(string filePath) 
 2 {
 3     Dictionary < string,List < string >> wordDict = new Dictionary < string,List < string >> ();
 4     StreamReader fs = new StreamReader(filePath, Encoding.Default);
 5     string line;
 6     while (!string.IsNullOrEmpty(line = fs.ReadLine())) {
 7         var key = SignWord(GetCleanString(line));
 8         if (wordDict.ContainsKey(key)) {
 9             wordDict[key].Add(line);
10         } else {
11             var list = new List < string > () {
12                 line
13             };
14             wordDict.Add(key, list);
15         }
16     }
17     fs.Close();
18     return wordDict;
19 }

这样,我们就将单词以签名为Key,放入到 Dictionary 中;当然,实际应用中,我们会以将Dictionary序列化到文本文件中,这样就不用每次使用时都算一次了;

PS:对于搜索方面的学习,都是看着论文什么的摸索前进,其中走了很多弯路和歪解,如果本文有什么纰漏或错误的地方,请指出和谅解,谢谢;

posted @ 2013-06-04 21:33  三度空间  阅读(1888)  评论(8编辑  收藏  举报