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}\n", 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 }

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

时间: 2024-10-06 01:07:01

KMP算法的实现的相关文章

KMP算法和next数组的c/c++实现

KMP算法基本思想有许多博客都写到了,写得也十分形象,不懂得可以参考下面的传送门,我就不解释基本思想了.本文主要给出KMP算法及next数组的计算方法(主要是很多网上的代码本人(相信应该是许多人吧)看不懂,直接拿来用也是各种问题),这里的代码封装性和优化都有待考究,但是基本能实现KMP算法 http://www.cnblogs.com/c-cloud/p/3224788.html 这里提醒各位看官,while循环次数不是常见的固定次数的循环,而是动态根据实际情况将大家固认为的“一趟循环”分解成几

万年历算法的实现(C语言--gcc编译)

/** cal.c * * 现行的格里历是从儒略历演化而来的.儒略历每4年一个润年,润年366天,平年365天.* 如果从公元1年算的话,那么凡是能够被4整除的都是润年.从天文角度看,儒略历这种 * 历法是有误差的,到16世纪误差已经达到了10天.1582年,罗马教皇对儒略历进行了 * 一次校定,该年的10-5到10-14这10天被抹掉,并规定凡不能被400整除的世纪年不再 * 算为润年,校定之后的儒略历即为现行的格里历. * * 但是英国直到1752年才开始使用格里历,此时时间误差已经达到了1

搜索引擎--范例:中英文混杂分词算法的实现--正向最大匹配算法的原理和实现

纯中文和中英文混杂的唯一区别是,分词的时候你如何辨别一个字符是英文字符还是孩子字符, 人眼很容易区分,但是对于计算机来说就没那么容易了,只要能辨别出中文字符和英文的字符,分词本身就不是一个难题 1:文本的编码问题: utf8:windows下,以utf8格式保存的文本是一个3个字节(以16进制)的BOM的,并且你不知道一个汉字是否是用3位表示,但是英文适合ascii编码一样的 ascii:英文一位,中文两位,并且中文的第一个字节的值是大于128和,不会和英文混淆,推荐 unicode:中文基本是

探讨排序算法的实现

排序算法是我们工作中使用最普遍的算法,常见的语言库中基本都会有排序算法的实现,比如c标准库的qsort,stl的sort函数等.本文首先介绍直接插入排序,归并排序,堆排序,快速排序和基数排序等比较排序算法,然后介绍计数排序,基数排序等具有线性时间的排序算法.本文主要讨论算法的实现方法,并不会过多介绍基本理论. 评价一个排序算法优劣适用与否,一般需要从三个方面来分析 时间复杂度.用比较操作和移动操作数的最高次项表示,由于在实际应用中最在乎的是运行时间的上限,所以一般取输入最坏情况的下的运行时间作为

Bug2算法的实现(RobotBASIC环境中仿真)

移动机器人智能的一个重要标志就是自主导航,而实现机器人自主导航有个基本要求--避障.之前简单介绍过Bug避障算法,但仅仅了解大致理论而不亲自动手实现一遍很难有深刻的印象,只能说似懂非懂.我不是天才,不能看几遍就理解理论中的奥妙,只能在别人大谈XX理论XX算法的时候,自己一个人苦逼的面对错误的程序问为什么... 下面开始动手来实现一下简单的Bug2避障算法.由于算法中涉及到机器人与外界环境的交互,因此需要选择一个仿真软件.常用的移动机器人仿真软件主要有Gazebo.V-rep.Webots.MRD

软考笔记第六天之各排序算法的实现

对于前面的排序算法,用c#来实现 直接插入排序: 每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序.第一趟比较前两个数,然后把第二个数按大小插入到有序表中: 第二趟把第三个数据与前两个数从前向后扫描,把第三个数按大小插入到有序表中:依次进行下去,进行了(n-1)趟扫描以后就完成了整个排序过程.直接插入排序属于稳定的排序,最坏时间复杂性为O(n^2),空间复杂度为O(1).直接插入排序是由两层嵌套循环组成的.外层循环标识并决定待比较的数值.内层循环为待比较数值确定其最终位

图像旋转算法的实现

上一篇转载的文章(http://blog.csdn.net/carson2005/article/details/36900161)介绍了图像旋转的原理,这里给出代码实现,具体原理请参考上面的链接: 实现代码: void ImgRotate(cv::Mat imgIn, float theta, cv::Mat& imgOut) { int oldWidth = imgIn.cols; int oldHeight = imgIn.rows; // 源图四个角的坐标(以图像中心为坐标系原点) fl

Canny边缘检测算法的实现

Canny原理 Canny的原理就不细说了,冈萨雷斯的<数字图像处理>(第三版)P463~465讲解的比较清楚,主要就四个步骤: 1. 对图像进行高斯滤波 2. 计算梯度大小和梯度方向 3. 对梯度幅值图像进行非极大抑制 4. 双阈值处理和连接性分析(通常这一步与非极大抑制并行,详见下面的代码) 下面重点说一下非极大抑制. 非极大抑制 对一幅图像计算梯度大小和梯度方向后,需要进行非极大抑制,一般都是通过计算梯度方向,沿着梯度方向,判断该像素点的梯度大小是否是极大值.这里主要说一下方向的判断.

Python 排序算法的实现

冒泡排序: 1 def bubble(l): 2 length = len(l) 3 for i in range(length): 4 for j in range(i+1, length): 5 if l[i] > l[j]: 6 l[i], l[j] = l[j], l[i] 7 print l 选择排序: 1 def select(l): 2 length = len(l) 3 for i in range(length): 4 minn = i 5 for j in range(i+1