/
levenshtein_distance.c
115 lines (80 loc) · 1.72 KB
/
levenshtein_distance.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*
* Copyright 2002 by Steven McDougall. This module is free
* software; you can redistribute it and/or modify it under the same
* terms as Perl itself.
*
*/
#include "common-internal.h"
#include "levenshtein_distance.h"
#include <stdlib.h>
#include <string.h>
static int _prefix_distance(char *A, char *B, int lA, int lB);
static int _min(int a, int b, int c);
static void score(int *pD, char *A, char *B, int lA, int lB);
#define D(r,c) pD[(r)*lB1+(c)]
int distance(char *A, char *B)
{
int *pD, d;
int lA = strlen(A);
int lB = strlen(B);
int lA1 = lA+1;
int lB1 = lB+1;
pD = (int *) malloc(lA1 * lB1 * sizeof(int));
if (!pD)
return -1;
score(pD, A, B, lA, lB);
d = D(lA,lB);
free(pD);
return d;
}
int prefix_distance(char *A, char *B)
{
int lA = strlen(A);
int lB = strlen(B);
return lA < lB ?
_prefix_distance(A, B, lA, lB) :
_prefix_distance(B, A, lB, lA);
}
static int _prefix_distance(char *A, char *B, int lA, int lB)
{
int *pD, c, d;
int lA1 = lA+1;
int lB1 = lB+1;
pD = (int *) malloc(lA1 * lB1 * sizeof(int));
if (!pD)
return -1;
score(pD, A, B, lA, lB);
d = D(lA, lA);
for (c = lA+1; c <= lB; c++)
if (d > D(lA, c))
d = D(lA, c);
free(pD);
return d;
}
static void score(int *pD, char *A, char *B, int lA, int lB)
{
int r, c;
int lB1 = lB+1;
for (r = 0; r <= lA; r++)
D(r,0) = r;
for (c = 0; c <= lB; c++)
D(0,c) = c;
for (r = 1; r <= lA; r++) {
for (c = 1; c <= lB; c++) {
int u = D(r-1,c );
int l = D(r ,c-1);
int ul = D(r-1,c-1);
int cost = (A[r-1] == B[c-1] ? 0 : 1);
D(r,c) = _min(u+1, l+1, ul+cost);
}
}
}
static int _min (int a, int b, int c)
{
int min = a;
if (min > b)
min = b;
if (min > c)
min = c;
return min;
}