Damerau-Levenshtein距离(用转置编辑距离)c实现

时间:2012-05-23 20:15:59

标签: c++ string string-matching levenshtein-distance

我在c ++中实现了Damerau-Levenshtein距离,但它没有为输入提供正确的o / p(pantera,aorta)正确的o / p为4但是我的代码给出了5 .....

int  editdist(string s,string t,int n,int m) 
{
    int d1,d2,d3,cost;
    int i,j;
    for(i=0;i<=n;i++) 
    {
        for(j=0;j<=m;j++)
        {
          if(s[i+1]==t[j+1]) 
              cost=0;
          else
              cost=1;
          d1=d[i][j+1]+1;
          d2=d[i+1][j]+1;
          d3=d[i][j]+cost;
          d[i+1][j+1]=minimum(d1,d2,d3);
          if(i>0 && j>0 && s[i+1]==t[j] && s[i]==t[j+1] )   //transposition
          {
              d[i+1][j+1]=min(d[i+1][j+1],d[i-1][j-1]+cost);
          }
        }
    }
    return d[n+1][m+1]; 
}

我没有看到任何错误。有人可以发现代码有问题吗?

3 个答案:

答案 0 :(得分:7)

帖子中的算法不计算Damerau-Levenshtein距离。在wikipedia article中,此算法被定义为最佳字符串对齐距离。

可以在另一个SO post中找到DL距离算法的java实现。

要获得正确的OSA距离值,请使用标有-

的行更改下面标有+的行
 int  editdist(string s,string t,int n,int m) 
 {
     int d1,d2,d3,cost;
     int i,j;
     for(i=0;i<=n;i++) 
     {
         for(j=0;j<=m;j++)
         {
-          if(s[i+1]==t[j+1]) 
+          if(s[i+1]==t[j+1]) 
              cost=0;
           else
              cost=1;
           d1=d[i][j+1]+1;
           d2=d[i+1][j]+1;
           d3=d[i][j]+cost;
           d[i+1][j+1]=minimum(d1,d2,d3);
-          if(i>0 && j>0 && s[i+1]==t[j] && s[i]==t[j+1] )   //transposition
+          if(i>0 && j>0 && s[i]==t[j-1] && s[i-1]==t[j] )   //transposition
           {
               d[i+1][j+1]=min(d[i+1][j+1],d[i-1][j-1]+cost);
           }
         }
     }
     return d[n+1][m+1]; 
 }

看起来代码是从用编程语言编写的程序中复制的,默认情况下数组索引从1开始。因此,对距离数组d的元素的所有引用都会递增。但是,对字符串中字符的引用是对基于0的数组的引用,因此不应更新它们。

要计算距离数组必须正确初始化的距离:

for( i = 0; i < n + 1; i++)
      d[i][0] = i;
for( j = 1; j < m + 1; j++)
      d[0][j] = j;

由于你得到了答案5,你可能已经正确地初始化了距离数组。

由于上述算法不计算DL距离,因此这里是DL算法的C实现的草图(来自SO帖子,带有从维基百科文章中的ActionScript impl。派生的java impl。)。 / p>

#define d(i,j) dd[(i) * (m+2) + (j) ]
#define min(x,y) ((x) < (y) ? (x) : (y))
#define min3(a,b,c) ((a)< (b) ? min((a),(c)) : min((b),(c)))
#define min4(a,b,c,d) ((a)< (b) ? min3((a),(c),(d)) : min3((b),(c),(d)))

int dprint(int* dd, int n,int m){
 int i,j;
 for (i=0; i < n+2;i++){
    for (j=0;j < m+2; j++){
        printf("%02d ",d(i,j));
    }
    printf("\n");
 }
 printf("\n");
 return 0;
}

int dldist2(char *s, char* t, int n, int m) {
    int *dd;
    int i, j, cost, i1,j1,DB;
    int INFINITY = n + m;
    int DA[256 * sizeof(int)];

    memset(DA, 0, sizeof(DA));

    if (!(dd = (int*) malloc((n+2)*(m+2)*sizeof(int)))) {
      return -1;
    }

    d(0,0) = INFINITY;
    for(i = 0; i < n+1; i++) {
      d(i+1,1) = i ;
      d(i+1,0) = INFINITY;
    }
    for(j = 0; j<m+1; j++) {
      d(1,j+1) = j ;
      d(0,j+1) = INFINITY;
    }      
    dprint(dd,n,m);

    for(i = 1; i< n+1; i++) {
      DB = 0;
      for(j = 1; j< m+1; j++) {
        i1 = DA[t[j-1]];
        j1 = DB;
        cost = ((s[i-1]==t[j-1])?0:1);
        if(cost==0) DB = j;
        d(i+1,j+1) =
          min4(d(i,j)+cost,
              d(i+1,j) + 1,
              d(i,j+1)+1, 
              d(i1,j1) + (i-i1-1) + 1 + (j-j1-1));
      }
      DA[s[i-1]] = i;
      dprint(dd,n,m);
    }
    cost = d(n+1,m+1);
    free(dd);
    return cost;
}

答案 1 :(得分:3)

以下是此算法的C ++版本:

int damerau_levenshtein_distance(std::string p_string1, std::string p_string2)
{
    int l_string_length1 = p_string1.length();
    int l_string_length2 = p_string2.length();
    int d[l_string_length1+1][l_string_length2+1];

    int i;
    int j;
    int l_cost;

    for (i = 0;i <= l_string_length1;i++)
    {
        d[i][0] = i;
    }
    for(j = 0; j<= l_string_length2; j++)
    {
        d[0][j] = j;
    }
    for (i = 1;i <= l_string_length1;i++)
    {
        for(j = 1; j<= l_string_length2; j++)
        {
            if( p_string1[i-1] == p_string2[j-1] )
            {
                l_cost = 0;
            }
            else
            {
                l_cost = 1;
            }
            d[i][j] = std::min(
            d[i-1][j] + 1,                  // delete
            std::min(d[i][j-1] + 1,         // insert
            d[i-1][j-1] + l_cost)           // substitution
            );
            if( (i > 1) && 
            (j > 1) && 
            (p_string1[i-1] == p_string2[j-2]) && 
            (p_string1[i-2] == p_string2[j-1])
            ) 
            {
            d[i][j] = std::min(
            d[i][j],
             d[i-2][j-2] + l_cost   // transposition
            );
            }
        }
    }
    return d[l_string_length1][l_string_length2];
}

答案 2 :(得分:0)

你的例子pantera,主动脉应该给5,你可以在这里测试https://code.hackerearth.com/0356acE

不仅仅是你的代码没有编译,这里是一个编译版本

using namespace std;
int  editdist(string s,string t,int n,int m) 
{
  int d1,d2,d3,cost;
  int i,j;
  int d[n + 1][m + 1];
  for(i=0;i<=n;i++) 
  {
    for(j=0;j<=m;j++)
    {
      if(s[i - 1]==t[j - 1]) 
        cost=0;
      else
        cost=1;
      d1=d[i][j+1]+1;
      d2=d[i+1][j]+1;
      d3=d[i][j]+cost;
      d[i+1][j+1]=min(min(d1,d2),d3);
      if(i>0 && j>0 && s[i+1]==t[j] && s[i]==t[j+1] )   //transposition
      {
        d[i+1][j+1]=min(d[i+1][j+1],d[i-1][j-1]+cost);
      }
   }
 }
 return d[n+1][m+1];  
} 

对于那些想要实现维基百科版本的人,[Wikiepadia link] wiki要小心。

for j := 1 to length(b) inclusive do
  if a[i] = b[j] then // should be replaced by if a[i - 1] = b[j - 1]

这是我自己的版本c ++

unsigned int lev_dam_dist(std::string s1,  std::string s2)
{
  size_t size1 = s1.size();
  size_t size2 = s2.size();
  size_t d[size1 + 1][size2 + 1];
  for (int i = 0; i <= size1; i ++)
    d[i][0] = i;
  for (int i = 0; i <= size2; i ++)
    d[0][i] = i;

  int cost = 0; 
  for (int i = 1; i <= size1; i ++)
    for (int j = 1; j <= size2; j ++)
    {      
      cost = (s1[i - 1] == s2[j - 1]) ? 0 : 1 ;
      if ( (i > 1) && (j > 1) && (s1[i] == s2[j - 1]) && (s1[i - 1] == s2[j]))
      {
        size_t a = std::min(d[i - 1][j], d[i][j - 1] + 1);
        size_t b = std::min(d[i][j] + cost, d[i - 2][j - 2]);
        d[i][j] = std::min(a, b);
      }
      else
      {
        d[i][j] = std::min(std::min(d[i][j -1] + 1, d[i - 1][j] + 1), d[i - 1][j - 1] + cost);
      }
    }
  return d[size1][size2];
}