私は、2 つの文字列の類似性を計算するためにレーベンシュタイン アルゴリズムを必要とするアプリケーションに取り組んでいます。
少し前に、C# バージョン (インターネットで簡単に見つけられる) を VB.NET に適合させたところ、次のようになりました。
Public Function Levenshtein1(s1 As String, s2 As String) As Double
Dim n As Integer = s1.Length
Dim m As Integer = s2.Length
Dim d(n, m) As Integer
Dim cost As Integer
Dim s1c As Char
For i = 1 To n
d(i, 0) = i
Next
For j = 1 To m
d(0, j) = j
Next
For i = 1 To n
s1c = s1(i - 1)
For j = 1 To m
If s1c = s2(j - 1) Then
cost = 0
Else
cost = 1
End If
d(i, j) = Math.Min(Math.Min(d(i - 1, j) + 1, d(i, j - 1) + 1), d(i - 1, j - 1) + cost)
Next
Next
Return (1.0 - (d(n, m) / Math.Max(n, m))) * 100
End Function
次に、微調整してパフォーマンスを向上させようとして、バージョンで終了しました。
Public Function Levenshtein2(s1 As String, s2 As String) As Double
Dim n As Integer = s1.Length
Dim m As Integer = s2.Length
Dim d(n, m) As Integer
Dim s1c As Char
Dim cost As Integer
For i = 1 To n
d(i, 0) = i
s1c = s1(i - 1)
For j = 1 To m
d(0, j) = j
If s1c = s2(j - 1) Then
cost = 0
Else
cost = 1
End If
d(i, j) = Math.Min(Math.Min(d(i - 1, j) + 1, d(i, j - 1) + 1), d(i - 1, j - 1) + cost)
Next
Next
Return (1.0 - (d(n, m) / Math.Max(n, m))) * 100
End Function
基本的に、距離の配列 d(,) は、2 つの初期 (および追加) サイクルを必要とする代わりに、サイクルのメイン内で初期化できると考えました。これは大きな改善になると本当に思っていました...残念ながら、オリジナルよりも改善されていないだけでなく、実際には動作が遅くなります!
生成された IL コードを見て両方のバージョンを分析しようとしましたが、理解できません。
だから、誰かがこの問題に光を当て、2 番目のバージョン (サイクル数が少ない場合でも) が元のバージョンよりも遅い理由を説明できることを望んでいましたか?
注: 時間差は約 0.15 ナノ秒です。これは大したことではないように見えますが、何千万もの文字列をチェックする必要がある場合、その違いは非常に顕著になります。