zoukankan      html  css  js  c++  java
  • KMP算法的实现

    今天看到了一篇关于KMP算法的讲解的文章,很难得,讲得非常清楚。分享给大家,希望对大家有帮助。http://kb.cnblogs.com/page/176818/

    我自己基于这个讲解的内容作了一个实现,效果还不错,码代码的功力有限,还请大家多指正其中可以改进的地方。

     1 using System.Collections.Generic;
     2 
     3 namespace KMPImplementation
     4 {
     5     /// <summary>
     6     /// 该类用于生成KMP算法中,需要用的部分匹配表
     7     /// </summary>
     8     public class PartialMatchTable
     9     {
    10         private string data;
    11         List<int> OffsetArray = new List<int>();
    12 
    13         /// <summary>
    14         /// 在构造函数中获得匹配模式,并计算产生部分匹配表
    15         /// </summary>
    16         /// <param name="para"></param>
    17         public PartialMatchTable(string para)
    18         {
    19             data = para;
    20             GenerateOffsetArray();
    21         }
    22 
    23         /// <summary>
    24         /// 计算一个字符串中,最长的相同前缀与后缀的长度
    25         /// </summary>
    26         /// <param name="str">需要计算的字符串</param>
    27         /// <returns>长度值</returns>
    28         private int GetMaxPrefixPostfixLength(string str)
    29         {
    30             int cnt = 0;
    31             if (str != null)
    32             {
    33                 int len = str.Length - 1;
    34                 for (int i = 1; i <= len; i++)
    35                 {
    36                     string pre = str.Substring(0, i);
    37                     string post = str.Substring(str.Length - i, i);
    38                     if (pre == post)
    39                         cnt = cnt < i ? i : cnt;
    40                 }
    41             }
    42             return cnt;
    43         }
    44 
    45         /// <summary>
    46         /// 计算给定字符串各个字符对应的偏移值
    47         /// </summary>
    48         private void GenerateOffsetArray()
    49         {
    50             if (string.IsNullOrEmpty(data))
    51                 return;
    52             if (data.Length == 1)
    53                 return;
    54             for (int i = 0; i < data.Length; i++)
    55             {
    56                 string sub = data.Substring(0, i + 1);
    57                 int max = GetMaxPrefixPostfixLength(sub);
    58                 OffsetArray.Add(max);
    59             }
    60         }
    61 
    62         /// <summary>
    63         /// 从部分匹配表中,取出相应的值
    64         /// </summary>
    65         /// <param name="i"></param>
    66         /// <returns></returns>
    67         public int GetOffset(int i)
    68         {
    69             int val = 0;
    70             if (OffsetArray.Count > i)
    71                 val = OffsetArray[i];
    72             return val;
    73         }
    74 
    75         /// <summary>
    76         /// 调试用的,打印计算结果
    77         /// </summary>
    78         public void PrintDic()
    79         {
    80             int cnt = data.Length;
    81             for (int i = 0; i < cnt; i++)
    82             {
    83                 System.Diagnostics.Debug.WriteLine("{0},{1}
    ", data[i], OffsetArray[i]);
    84             }
    85         }
    86     }
    87 }
      1 using System.Collections.Generic;
      2 
      3 namespace KMPImplementation
      4 {
      5     /// <summary>
      6     /// 该类实现了KMP匹配算法,以此在目标串中查找匹配模式的index
      7     /// </summary>
      8     public class KMPImplementation
      9     {
     10         private string pattern; // 记录模式
     11         private string data;// 记录目标串
     12         PartialMatchTable si;// 记录部分匹配表
     13 
     14         /// <summary>
     15         /// 在构造函数中,将异常的输入,如null,过滤处理
     16         /// </summary>
     17         /// <param name="dt">需要匹配的目标串</param>
     18         /// <param name="ptn">匹配模式</param>
     19         public KMPImplementation(ref string dt, string ptn)
     20         {
     21             si = new PartialMatchTable(ptn);
     22             if (dt == null || ptn == null)
     23             {
     24                 data = string.Empty;
     25                 pattern = string.Empty;
     26             }
     27             else
     28             {
     29                 data = dt;
     30                 pattern = ptn;
     31             }
     32         }
     33 
     34         /// <summary>
     35         /// 查找目标串中的第一个匹配项的index
     36         /// </summary>
     37         /// <returns></returns>
     38         public int FindFirstIndex()
     39         {
     40             int idx = -1;
     41             int datalen = data.Length;
     42             int patternlen = pattern.Length;
     43             // 空串查找空串的情况
     44             if (datalen == patternlen && patternlen == 0)
     45                 return 0;
     46             // 对应目标串比模式短的情况,直接返回找不到,即是-1
     47             if (datalen >= patternlen)
     48             {
     49                 datalen = datalen - patternlen;
     50                 for (int i = 0; i <= datalen; )
     51                 {
     52                     for (int j = 0; j < patternlen; )
     53                     {
     54                         if (data[i + j] == pattern[j])// 模式与目标串的字符相同,继续比较下一个
     55                         {
     56                             j++;
     57                             if (j == patternlen)// 当模式的index指到了最后一个位置,表明查找到了
     58                                 return i;
     59                         }
     60                         else// 当模式与目标串不匹配时
     61                         {
     62                             if (j == 0)// 如果第一个字符都不匹配,继续比较下一个位置
     63                                 i++;
     64                             else
     65                                 i += j - si.GetOffset(j - 1);// 如果已经发生了部分匹配,查找部分匹配表来确定,当前应该将目标串的index向后移动的量
     66                             break;
     67                         }
     68                     }
     69                 }
     70             }
     71             return idx;
     72         }
     73 
     74         /// <summary>
     75         /// 查找目标串中的所有匹配项的index,以List形式返回
     76         /// </summary>
     77         /// <returns></returns>
     78         public List<int> FindAllIndex()
     79         {
     80             List<int> list = new List<int>();
     81             int datalen = data.Length;
     82             int patternlen = pattern.Length;
     83             // 空串查找空串的情况
     84             if (datalen == patternlen && patternlen == 0)
     85             {
     86                 list.Add(0);
     87                 return list;
     88             }
     89             // 对应目标串比模式短的情况,直接返回找不到,即是-1
     90             if (datalen >= patternlen)
     91             {
     92                 datalen = datalen - patternlen;
     93                 for (int i = 0; i <= datalen; )
     94                 {
     95                     for (int j = 0; j < patternlen; )
     96                     {
     97                         if (data[i + j] == pattern[j])// 模式与目标串的字符相同,继续比较下一个
     98                         {
     99                             j++;
    100                             if (j == patternlen)// 当模式的index指到了最后一个位置,表明查找到了
    101                             {
    102                                 list.Add(i);
    103                                 i++;
    104                             }
    105                         }
    106                         else// 当模式与目标串不匹配时
    107                         {
    108                             if (j == 0)// 如果第一个字符都不匹配,继续比较下一个位置
    109                                 i++;
    110                             else
    111                                 i += j - si.GetOffset(j - 1);// 如果已经发生了部分匹配,查找部分匹配表来确定,当前应该将目标串的index向后移动的量
    112                             break;
    113                         }
    114                     }
    115                 }
    116             }
    117             if (list.Count == 0)
    118                 list.Add(-1);
    119             return list;
    120         }
    121     }
    122 }

    这里实现了两个方法,一个是查找第一个匹配项,一个是查找所有的匹配项,方便调用;但是,显而易见的是,两个方法有太多的相同的地方,可以再做一次抽象。懒病犯了,就没接着改进了。

  • 相关阅读:
    行盒(line box)垂直方向的属性详解:从font-size、line-height到vertical-align
    CSS绝对定位的原点:是在border上、padding上还是在content上?
    从知乎首页用户操作入口学习到的CSS技巧
    重置表单中的文件上传控件(file input)的方法
    ASCII, Unicode, UTF-8, 8进制, 16进制等各种编码学习理解笔记
    Yarn的Linking dependencies特别慢的优化方法
    MongoDB学习记录(四)
    MongoDB学习记录(三)
    MongoDB学习记录(二)
    AdBlock——拦截网页广告
  • 原文地址:https://www.cnblogs.com/warnet/p/4330953.html
Copyright © 2011-2022 走看看