簡單的英文變位詞聚類算法


有時,簡單的算法也有其實用的意義,由於之前公司內部搜索引擎優化的需要,我根據《編程珠璣》中查找英文單詞變位詞的算法,來實現搜索糾錯的功能。

在搜索時,有時記不住單詞,會出現拼寫錯誤的情況,例如,搜索“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:對於搜索方面的學習,都是看着論文什么的摸索前進,其中走了很多彎路和歪解,如果本文有什么紕漏或錯誤的地方,請指出和諒解,謝謝;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM