C#实现字符串匹配算法

本文介绍了在C#中实现几种经典的字符串匹配算法,包括BF算法和MP算法。BF算法通过逐个字符比较实现匹配,当匹配失败时,主串回溯。MP算法则优化了BF算法,避免主串回溯,只利用模式串的回溯进行匹配。详细阐述了两种算法的工作原理,并给出了C#代码实现。
摘要由CSDN通过智能技术生成

最近在学习算法。刚学习完字符串匹配的几种算法:BF算法、MP算法:KMP算法,BM算法和BMH算法。参考的书籍是算法之美,原书的代码都是用C++写的。我不懂C++,只学过C#,这里就用C#做个总结(自己是个菜鸟,表达错误的地方,希望大家指正)。

1、BF算法

 BF算法实现原理是:从主串和模式串的首位置开始,依次比较主串和模式串的各个位置,如果匹配错误,主串就返回第二个位置,模式串返回首位置,重新匹配。以此类推,直到模式串匹配成功,返回匹配成功的位置。如果没有发生匹配就返回-1。

代码如下:

 public static  int MatchStr(string s1, string s2,int n)
        {
            int i = n-1, j = 0;            
//n为匹配的起始位置
            bool IsMatch=false ;            
            while (!IsMatch)
            {
            if (s1[i] == s2[j])             
                {                 
                    i++;
                    j++;                  
                }
                else                        
                {
                    i = i - j + 1;
                    j = 0;
                }
 //如果模式串匹配成功,j++,就会得到模式串长度的值。
                if (j == s2.Length)         
                {
                    IsMatch = true;
                    n = i - j+1;                   
                } 
            }
   

  if (IsMatch)
            {
                Console.WriteLine("普通方法匹配成功");
            }
            else
            {
                n = -1;
                Console.WriteLine("普通方法匹配失败");
            }       
            return n;
        }

2、MP算法

 BF算法一旦匹配失败,i,j的值就会频繁的回溯,导致复杂度增大。MP算法避免的i值回溯,只利用j值的回溯进行匹配。

MP算法原理:模式串与主串进行匹配,进行到i处(模式串在j处)发现不匹配,如果模式串j处之前有前缀n个字符与主串i处

之前n个字符相匹配,则可将模式串j移动到n处,重新与i进行匹配(此时i的位置不变)即可。依次类推,直到匹配结束。

 现在的问题就是求n的值为多少。

 假设模式串与主串在i处不匹配(模式串在j处),那么说明主串的s1[i-j~i-1]的子串与模式串的s2[0~j-1]是匹配成功的。那么寻找

主串i之前的n个字符,等价于寻找模式串j之前的n个字符与模式串的前缀n个字符是相匹配的,即n的值与主串无关,只与模式串自

身的j位置有关。n的计算方法计算如下:假定模式串为(ababcabababc)

当j=0时,代表第一个字符就匹配失败,规定此时n为-1;
当j=1时,代表第二个字符匹配失败。此时n为0;
当j=2时,则是在aba处匹配失败,前面并不能找到合格的n。则n为0;
当j=3时,则是在abab处匹配失败,则首字母a与j-1处的a是匹配的,则此时n为1;
当j=4时,则是在ababc处匹配失败,则前缀ab,与j-2~j-1处ab匹配,则此时n为2;
......
我们发现,j处的n值与j-1处的n值有关。
推理如下:
假设j-1处匹配失败,值为n,意思是:s2[0~n-1]=s2[j-1-n~j-2]。
若在j处匹配失败,有两种情况:
情况1:s2[j-1]=s2[n],那么s2[0~n]=s2[j-1-n~j-1],此时可得到j处匹配失败的n值为n+1;
情况2:s2[j-1]!=s2[n]。那么说明匹配成功的前缀字符一定不是n+1,但是会不会有更小的前缀字符匹配成功。
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
你可以使用C#的字符串比较方法来计算两个字符串之间的相似度。常用的算法有Levenshtein距离和Jaro-Winkler距离。下面是使用这两种算法计算字符串相似度的示例代码: ```csharp using System; class Program { static void Main(string[] args) { string str1 = "hello"; string str2 = "hallo"; double levenshteinDistance = LevenshteinDistance(str1, str2); double jaroWinklerDistance = JaroWinklerDistance(str1, str2); Console.WriteLine("Levenshtein Distance: " + levenshteinDistance); Console.WriteLine("Jaro-Winkler Distance: " + jaroWinklerDistance); } static double LevenshteinDistance(string s, string t) { int n = s.Length; int m = t.Length; int[,] d = new int[n + 1, m + 1]; if (n == 0) { return m; } if (m == 0) { return n; } for (int i = 0; i <= n; i++) { d[i, 0] = i; } for (int j = 0; j <= m; j++) { d[0, j] = j; } for (int j = 1; j <= m; j++) { for (int i = 1; i <= n; i++) { int cost = (s[i - 1] == t[j - 1]) ? 0 : 1; d[i, j] = Math.Min(Math.Min( d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost); } } return 1.0 - (double)d[n, m] / Math.Max(n, m); } static double JaroWinklerDistance(string s, string t) { int sLen = s.Length; int tLen = t.Length; if (sLen == 0 && tLen == 0) { return 1.0; } int matchDistance = Math.Max(sLen, tLen) / 2 - 1; bool[] sMatches = new bool[sLen]; bool[] tMatches = new bool[tLen]; int matches = 0; for (int i = 0; i < sLen; i++) { int start = Math.Max(0, i - matchDistance); int end = Math.Min(i + matchDistance + 1, tLen); for (int j = start; j < end; j++) { if (tMatches[j]) { continue; } if (s[i] != t[j]) { continue; } sMatches[i] = true; tMatches[j] = true; matches++; break; } } if (matches == 0) { return 0.0; } int tPrefix = 0; for (int i = 0; i < tLen && tMatches[i]; i++) { tPrefix++; } double jaro = ((double)matches / sLen + (double)matches / tLen + (double)(matches - tPrefix) / matches) / 3; int j = 0; while (j < Math.Min(sLen, 4) && s[j] == t[j]) { j++; } if (j == 0) { return jaro; } double jaroWinkler = jaro + Math.Min(0.1, 1.0 / Math.Max(sLen, tLen) * j * (1.0 - jaro)); return jaroWinkler; } } ``` 在上面的示例中,`LevenshteinDistance`方法使用Levenshtein距离算法计算字符串相似度,并返回一个介于0和1之间的值。这个值越接近1,表示两个字符串越相似。 `JaroWinklerDistance`方法使用Jaro-Winkler距离算法计算字符串相似度,并返回一个介于0和1之间的值。这个值越接近1,表示两个字符串越相似。Jaro-Winkler距离算法还考虑了字符串的前缀匹配,因此对于具有相同前缀的字符串,它的结果会更准确。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值