【发布时间】:2010-11-23 20:08:32
【问题描述】:
晚安,
我一直在使用模糊字符串匹配一段时间,并且使用带有一些指针的 C 语言我可以编写一个非常快速的(满足我的需要)两个字符串之间的 Levenshtein 距离的实现。我尝试使用不安全代码和 fixed 关键字将代码移植到 C#,但性能要慢得多。所以我选择构建一个 C++ dll 并使用 C# 中的[DllImport],自动编组每个字符串。问题是,在分析之后,这一直是我的程序中最耗时的部分,占程序总运行时间的 50-57%。因为我认为我需要对来自大约 300 万条数据库记录的文本字段的大量子字符串做一些繁重的工作,所以我认为 Levenshtein 距离所花费的时间几乎是不可接受的。既然如此,我想知道您对下面的代码是否有任何建议,无论是算法还是编程相关,或者您是否知道任何更好的算法来计算这个距离?
#define Inicio1 (*(BufferVar))
#define Inicio2 (*(BufferVar+1))
#define Fim1 (*(BufferVar+2))
#define Fim2 (*(BufferVar+3))
#define IndLinha (*(BufferVar+4))
#define IndCol (*(BufferVar+5))
#define CompLinha (*(BufferVar+6))
#define TamTmp (*(BufferVar+7))
int __DistanciaEdicao (char * Termo1, char * Termo2, int TamTermo1, int TamTermo2, int * BufferTab, int * BufferVar)
{
*(BufferVar) = *(BufferVar + 1) = 0;
*(BufferVar + 2) = TamTermo1 - 1;
*(BufferVar + 3) = TamTermo2 - 1;
while ((Inicio1 <= *(BufferVar + 2)) && (Inicio2 <= *(BufferVar + 3)) && *(Termo1 + Inicio1) == *(Termo2 + Inicio2))
Inicio1 = ++Inicio2;
if (Inicio2 > Fim2) return (Fim1 - Inicio1 + 1);
while ((Fim1 >= 0) && (Fim2 >= 0) && *(Termo1 + Fim1) == *(Termo2 + Fim2))
{ Fim1--; Fim2--;}
if (Inicio2 > Fim2) return (Fim1 - Inicio1 + 1);
TamTermo1 = Fim1 - Inicio1 + 1;
TamTermo2 = Fim2 - Inicio2 + 1;
CompLinha = ((TamTermo1 > TamTermo2) ? TamTermo1 : TamTermo2) + 1;
for (IndLinha = 0; IndLinha <= TamTermo2; *(BufferTab + CompLinha * IndLinha) = IndLinha++);
for (IndCol = 0; IndCol <= TamTermo1; *(BufferTab + IndCol) = IndCol++);
for (IndCol = 1; IndCol <= TamTermo1; IndCol++)
for (IndLinha = 1; IndLinha <= TamTermo2; IndLinha++)
*(BufferTab + CompLinha * IndLinha + IndCol) = ((*(Termo1 + (IndCol + Inicio1 - 1)) == *(Termo2 + (IndLinha + Inicio2 - 1))) ? *(BufferTab + CompLinha * (IndLinha - 1) + (IndCol - 1)) : ((*(BufferTab + CompLinha * (IndLinha - 1) + IndCol) < *(BufferTab + CompLinha * (IndLinha - 1) + (IndCol - 1))) ? ((*(BufferTab + CompLinha * IndLinha + (IndCol - 1)) < *(BufferTab + CompLinha * (IndLinha - 1) + IndCol)) ? *(BufferTab + CompLinha * IndLinha + (IndCol - 1)) : *(BufferTab + CompLinha * (IndLinha - 1) + IndCol)) : ((*(BufferTab + CompLinha * IndLinha + (IndCol - 1)) < *(BufferTab + CompLinha * (IndLinha - 1) + (IndCol - 1))) ? *(BufferTab + CompLinha * IndLinha + (IndCol - 1)) : *(BufferTab + CompLinha * (IndLinha - 1) + (IndCol - 1)))) + 1);
return *(BufferTab + CompLinha * TamTermo2 + TamTermo1);
}
请注意,BufferVar 和 BufferTab 是两个外部 int *(在这种情况下,int[] 变量是从 C# 编组的),我不会在每个函数调用中实例化它们以加快整个过程。尽管如此,这段代码对于我的需求来说还是很慢的。谁能给我一些建议,或者如果可能的话,提供一些更好的代码?
编辑:距离不能有界,我需要实际距离。
非常感谢,
【问题讨论】:
-
您确定需要 每个 词对之间的 Levenshtein 距离吗?如果考虑每一对,那是 9,000,000,000,000 距离。你真的需要计算所有这些吗?您将在哪里以及如何存储结果?例如,仅计算每个单词的前 3 个最接近的匹配就足够了吗?你真正想解决什么问题?
-
这不是这 160000 个单词中每对单词之间的距离。它是用户可以输入的每对可能的单词之间的实际距离。我已经更正了。
-
您的分析是否指出任何特别耗时的行?
-
此外,内循环线非常长且不可读,就目前而言。
-
短代码!= 快速代码。
标签: c++ c algorithm performance levenshtein-distance