Levenshtein距离,三种口味

通过迈克尔吉兰德,梅里亚姆公园软件

这篇短文的目的是描述勒文斯坦距离算法并展示如何在三种不同的编程中实现语言。

什么是列文斯坦距离?
演示
算法
源代码,三个口味
工具书类
其他口味


什么是列文斯坦距离?

Levenshtein距离(LD)是两个字符串之间相似性的度量,我们将其称为源字符串和目标字符串。这个距离是需要删除、插入或替换的次数将s变换为t。例如,

越大Levenshtein距离越大,弦的差异越大。

列文斯坦距离是以俄罗斯科学家弗拉基米尔的名字命名的勒文斯坦于1965年设计了该算法。如果你不会拼写或发音Levenshtein的度量有时也称为编辑距离。

Levenshtein距离算法已用于:


演示

下面的简单Java小程序允许您使用不同的字符串并计算其Levenshtein距离:


算法

步骤

步骤 描述
1 设置n为s的长度。
设置m为t的长度。
如果n=0,返回m并退出。
如果m=0,则返回n并退出。
构造一个包含0..m行和0..n列的矩阵。
2 将第一行初始化为0..n。
将第一列初始化为0..米。
检查s(i从1到n)的每个字符。
4 检查t(j从1到m)的每个字符。
5 如果s[i]等于t[j],则成本为0。
如果s[i]不等于t[j]成本为1。
6 将矩阵的单元格d[i,j]设置为以下最小值:
a.电池正上方加1:d[i-1,j]+1。
b.电池立即到达左加1:d[i,j-1]+1。
c.左上方对角的单元格加上成本:d[i-1,j-1]+成本。
7 迭代步骤(3、4、5、6)完成后,距离为在单元格d中发现[n,m]。

例子

本节显示了Levenshtein距离当源字符串为“GUMBO”而目标字符串为“GAMBOL”时计算。

步骤1和2

    G公司 单位 M(M) B类 O(运行)
  0 1 2 4 5
G公司 1          
A类 2          
M(M)          
B类 4          
O(运行) 5          
L(左) 6          

当i=1时,步骤3至6

    G公司 单位 M(M) B类 O(运行)
  0 1 2 4 5
G公司 1 0        
A类 2 1        
M(M) 2        
B类 4        
O(运行) 5 4        
L(左) 6 5        

当i=2时,步骤3至6

    G公司 单位 M(M) B类 O(运行)
  0 1 2 4 5
G公司 1 0 1      
A类 2 1 1      
M(M) 2 2      
B类 4      
O(运行) 5 4 4      
L(左) 6 5 5      

步骤3至6当i=3时

    G公司 单位 M(M) B类 O(运行)
  0 1 2 4 5
G公司 1 0 1 2    
A类 2 1 1 2    
M(M) 2 2 1    
B类 4 2    
O(运行) 5 4 4    
L(左) 6 5 5 4    

当i=4时,步骤3至6

    G公司 单位 M(M) B类 O(运行)
  0 1 2 4 5
G公司 1 0 1 2  
A类 2 1 1 2  
M(M) 2 2 1 2  
B类 4 2 1  
O(运行) 5 4 4 2  
L(左) 6 5 5 4  

当i=5时,步骤3至6

    G公司 单位 M(M) B类 O(运行)
  0 1 2 4 5
G公司 1 0 1 2 4
A类 2 1 1 2 4
M(M) 2 2 1 2
B类 4 2 1 2
O(运行) 5 4 4 2 1
L(左) 6 5 5 4 2

第7步

距离位于矩阵的右下角,即2。这个对应于我们的直觉认识,“GUMBO”可以转换为“GAMBOL”,将“U”替换为“A”,并添加“L”(一个替换,一个替换插入=2次更改)。


源代码,三种风格

每当工程师讨论编程语言。一个典型的断言是Allen Holub在JavaWorld中的声明文章(1999年7月):“例如,Visual Basic根本不是面向对象的。Microsoft基础类(MFC)和大多数其他Microsoft声称是面向对象的技术。"

来自不同方向的齐射是Simson Garfinkels的文章2001年1月8日,在题为“Java:缓慢、丑陋、无关紧要”的沙龙中开幕用“我讨厌Java”这个明确的词。

我们宁愿在这些宗教战争中采取中立立场。作为一种实践重要的是,如果一个问题可以用一种编程语言解决,您通常可以也可以用另一种方法解决。一个好的程序员能够从一种语言转向另一种语言而学习一门全新的语言不应该提出任何重大困难。编程语言是实现结束,而不是结束本身。

作为这一中立原则的适度例证,我们提供了资料来源以下代码实现了Levenshtein距离算法编程语言:


Java语言

公共课距离{//****************************//获取三个值中的最小值//****************************private int最小值(int a,int b,int c){int mi;mi=a;如果(b<mi){mi=b;}如果(c<mi){mi=c;}返回mi;}//*****************************//计算Levenshtein距离//*****************************public int LD(字符串s,字符串t){int d[][];//矩阵整数n;//s的长度整数m;//t的长度整数i;//迭代s整数j;//迭代t字符s_i;//s的第i个字符字符tj;//t的j特征int成本;//成本//第1步n=s.长度();m=t.长度();如果(n==0){返回m;}如果(m==0){返回n;}d=新整数[n+1][m+1];//第2步对于(i=0;i<=n;i++){d[i][0]=i;}对于(j=0;j<=m;j++){d[0][j]=j;}//步骤3对于(i=1;i<=n;i++){s_i=s.charAt(i-1);//第4步对于(j=1;j<=m;j++){t_j=t.charAt(j-1);//第5步如果(si==tj){成本=0;}其他{成本=1;}//第6步d[i][j]=最小值(d[i-1][j]+1,d[i][j-1]+1,d[i-1][j-1]+成本);}}//第7步返回d[n][m];}}

C类++

在C++中,数组的大小必须是常量,并且此代码片段在编译时导致错误:

整数sz=5;整数arr[sz];

这个限制使得下面的C++代码比如果矩阵可以简单地声明为二维数组,大小在运行时确定。

这里是定义等级(distance.h):

类距离{公众:int LD(字符常量*s,字符常量*t);私人:int最小值(int a,int b,int c);int*GetCellPointer(int*pOrigin,int col,int row,int nCols);int GetAt(int*pOrigin,int col,int row,int nCols);void PutAt(int*pOrigin,int col,int row,int nCols,int x);};

这里是实施类别(distance.cpp):

#包括“distance.h”#包括<string.h>#包括<malloc.h>//****************************//获取至少三个值//****************************int距离::最小值(int a,int b,int c){整数mi;mi=a;如果(b<mi){mi=b;}如果(c<mi){mi=c;}返回mi;}//**************************************************//获取指向矩阵中指定单元格的指针//************************************************** int*距离::GetCellPointer(int*pOrigin,int col,int row,int nCols){return pOrigin+col+(行*(nCols+1));}//*****************************************************//获取矩阵中指定单元格的内容//*****************************************************int距离::GetAt(int*pOrigin,int col,int row,int nCols){int*pCell;pCell=获取单元格指针(pOrigin,col,row,nCols);return*pCell;}//*******************************************************//用值x填充矩阵中的指定单元格//*******************************************************void距离::PutAt(int*pOrigin,int col,int row,int nCols,int x){int*pCell;pCell=获取单元格指针(pOrigin,col,row,nCols);*p细胞=x;}//*****************************//计算Levenshtein距离//*****************************int距离::LD(char const*s,char const*t){整数*d;//指向矩阵的指针整数n;//s的长度整数m;//t的长度整数i;//迭代s整数j;//遍历t字符s_i;//s的第i个字符字符t_j;//t的j特征int成本;//成本int结果;//结果int单元格;//目标单元格内容int以上;//上方单元格内容剩余int;//单元格内容立即向左int诊断;//左上方单元格内容int sz;//矩阵中的单元数//第1步n=结构;m=斯特伦(t);如果(n==0){返回m;}如果(m==0){返回n;}sz=(n+1)*(m+1)*大小(int);d=(int*)malloc(sz);//第2步对于(i=0;i<=n;i++){PutAt(d,i,0,n,i);}对于(j=0;j<=m;j++){PutAt(d,0,j,n,j);}//步骤3对于(i=1;i<=n;i++){s_i=s[i-1];//第4步对于(j=1;j<=m;j++){tj=t[j-1];//第5步如果(si==tj){成本=0;}其他{成本=1;}//第6步above=GetAt(d,i-1,j,n);left=GetAt(d,i,j-1,n);diag=GetAt(d,i-1,j-1,n);cell=最小值(上方+1,左侧+1,diag+cost);PutAt(d,i,j,n,cell);}}//第7步结果=GetAt(d,n,m,n);免费(d);返回结果;}

Visual Basic

'*******************************'***至少获取三个值'*******************************私有函数最小值(ByVal a作为整数_ByVal b作为整数_ByVal c作为整数)作为整数Dim mi为整数mi=a如果b<mi,则mi=bEnd If(结束条件)如果c<mi,则mi=cEnd If(结束条件)最小值=miEnd函数'********************************'***计算Levenshtein距离'********************************公共函数LD(ByVal s作为字符串,ByVal t作为字符串)作为整数Dim d()As Integer矩阵尺寸m为t的整数长度Dim n As Integer'长度sDim i As Integer'遍历sDim j As Integer'遍历tDim s_i As String'包含s个字符Dim t_j作为字符串't的第j个字符Dim cost As Integer成本'步骤1n=长度m=长度(t)如果n=0,则LD=米退出功能End If(结束条件)如果m=0,则LD=n退出功能End If(结束条件)将d(0到n,0到m)重定为整数'步骤2对于i=0到nd(i,0)=i接下来i对于j=0至md(0,j)=j下一个j'步骤3对于i=1到ns_i=中间$(s,i,1)'步骤4对于j=1至mt_j=中间$(t,j,1)'步骤5如果s_i=t_j,则成本=0其他成本=1End If(结束条件)'步骤6d(i,j)=最小值下一个j接下来i'步骤7LD=d(n,m)擦除dEnd函数

工具书类

其他讨论Levenshtein距离可在以下位置找到:

其他口味

以下人员已同意实施在这里可以使用各种语言的Levenstein距离算法:

这些页面之外的其他实现包括: