今天看到了一篇关于KMP算法的讲解的文章,很难得,讲得非常清楚。分享给大家,希望对大家有帮助。http://kb.cnblogs.com/page/176818/
我自己基于这个讲解的内容作了一个实现,效果还不错,码代码的功力有限,还请大家多指正其中可以改进的地方。
using System.Collections.Generic; namespace KMPImplementation
{
/// <summary>
/// 该类用于生成KMP算法中,需要用的部分匹配表
/// </summary>
public class PartialMatchTable
{
private string data;
List<int> OffsetArray = new List<int>(); /// <summary>
/// 在构造函数中获得匹配模式,并计算产生部分匹配表
/// </summary>
/// <param name="para"></param>
public PartialMatchTable(string para)
{
data = para;
GenerateOffsetArray();
} /// <summary>
/// 计算一个字符串中,最长的相同前缀与后缀的长度
/// </summary>
/// <param name="str">需要计算的字符串</param>
/// <returns>长度值</returns>
private int GetMaxPrefixPostfixLength(string str)
{
int cnt = ;
if (str != null)
{
int len = str.Length - ;
for (int i = ; i <= len; i++)
{
string pre = str.Substring(, i);
string post = str.Substring(str.Length - i, i);
if (pre == post)
cnt = cnt < i ? i : cnt;
}
}
return cnt;
} /// <summary>
/// 计算给定字符串各个字符对应的偏移值
/// </summary>
private void GenerateOffsetArray()
{
if (string.IsNullOrEmpty(data))
return;
if (data.Length == )
return;
for (int i = ; i < data.Length; i++)
{
string sub = data.Substring(, i + );
int max = GetMaxPrefixPostfixLength(sub);
OffsetArray.Add(max);
}
} /// <summary>
/// 从部分匹配表中,取出相应的值
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
public int GetOffset(int i)
{
int val = ;
if (OffsetArray.Count > i)
val = OffsetArray[i];
return val;
} /// <summary>
/// 调试用的,打印计算结果
/// </summary>
public void PrintDic()
{
int cnt = data.Length;
for (int i = ; i < cnt; i++)
{
System.Diagnostics.Debug.WriteLine("{0},{1}\n", data[i], OffsetArray[i]);
}
}
}
}
using System.Collections.Generic; namespace KMPImplementation
{
/// <summary>
/// 该类实现了KMP匹配算法,以此在目标串中查找匹配模式的index
/// </summary>
public class KMPImplementation
{
private string pattern; // 记录模式
private string data;// 记录目标串
PartialMatchTable si;// 记录部分匹配表 /// <summary>
/// 在构造函数中,将异常的输入,如null,过滤处理
/// </summary>
/// <param name="dt">需要匹配的目标串</param>
/// <param name="ptn">匹配模式</param>
public KMPImplementation(ref string dt, string ptn)
{
si = new PartialMatchTable(ptn);
if (dt == null || ptn == null)
{
data = string.Empty;
pattern = string.Empty;
}
else
{
data = dt;
pattern = ptn;
}
} /// <summary>
/// 查找目标串中的第一个匹配项的index
/// </summary>
/// <returns></returns>
public int FindFirstIndex()
{
int idx = -;
int datalen = data.Length;
int patternlen = pattern.Length;
// 空串查找空串的情况
if (datalen == patternlen && patternlen == )
return ;
// 对应目标串比模式短的情况,直接返回找不到,即是-1
if (datalen >= patternlen)
{
datalen = datalen - patternlen;
for (int i = ; i <= datalen; )
{
for (int j = ; j < patternlen; )
{
if (data[i + j] == pattern[j])// 模式与目标串的字符相同,继续比较下一个
{
j++;
if (j == patternlen)// 当模式的index指到了最后一个位置,表明查找到了
return i;
}
else// 当模式与目标串不匹配时
{
if (j == )// 如果第一个字符都不匹配,继续比较下一个位置
i++;
else
i += j - si.GetOffset(j - );// 如果已经发生了部分匹配,查找部分匹配表来确定,当前应该将目标串的index向后移动的量
break;
}
}
}
}
return idx;
} /// <summary>
/// 查找目标串中的所有匹配项的index,以List形式返回
/// </summary>
/// <returns></returns>
public List<int> FindAllIndex()
{
List<int> list = new List<int>();
int datalen = data.Length;
int patternlen = pattern.Length;
// 空串查找空串的情况
if (datalen == patternlen && patternlen == )
{
list.Add();
return list;
}
// 对应目标串比模式短的情况,直接返回找不到,即是-1
if (datalen >= patternlen)
{
datalen = datalen - patternlen;
for (int i = ; i <= datalen; )
{
for (int j = ; j < patternlen; )
{
if (data[i + j] == pattern[j])// 模式与目标串的字符相同,继续比较下一个
{
j++;
if (j == patternlen)// 当模式的index指到了最后一个位置,表明查找到了
{
list.Add(i);
i++;
}
}
else// 当模式与目标串不匹配时
{
if (j == )// 如果第一个字符都不匹配,继续比较下一个位置
i++;
else
i += j - si.GetOffset(j - );// 如果已经发生了部分匹配,查找部分匹配表来确定,当前应该将目标串的index向后移动的量
break;
}
}
}
}
if (list.Count == )
list.Add(-);
return list;
}
}
}
这里实现了两个方法,一个是查找第一个匹配项,一个是查找所有的匹配项,方便调用;但是,显而易见的是,两个方法有太多的相同的地方,可以再做一次抽象。懒病犯了,就没接着改进了。
KMP算法的实现的更多相关文章
-
C++经典KMP算法的实现
#include <iostream> #include <algorithm> #include <vector> #include <string> ...
-
KMP算法的实现(Java语言描述)
标签:it KMP算法是模式匹配专用算法. 它是在已知模式串的next或nextval数组的基础上执行的.如果不知道它们二者之一,就没法使用KMP算法,因此我们需要计算它们. KMP算法由两部分组成: ...
-
【字符串匹配】KMP算法和next数组的c/c++实现
KMP算法基本思想有许多博客都写到了,写得也十分形象,不懂得可以参考下面的传送门,我就不解释基本思想了.本文主要给出KMP算法及next数组的计算方法(主要是很多网上的代码本人(相信应该是许多人吧)看 ...
-
Bug2算法的实现(RobotBASIC环境中仿真)
移动机器人智能的一个重要标志就是自主导航,而实现机器人自主导航有个基本要求--避障.之前简单介绍过Bug避障算法,但仅仅了解大致理论而不亲自动手实现一遍很难有深刻的印象,只能说似懂非懂.我不是天才,不 ...
-
Canny边缘检测算法的实现
图像边缘信息主要集中在高频段,通常说图像锐化或检测边缘,实质就是高频滤波.我们知道微分运算是求信号的变化率,具有加强高频分量的作用.在空域运算中来说,对图像的锐化就是计算微分.由于数字图像的离散信号, ...
-
java基础解析系列(四)---LinkedHashMap的原理及LRU算法的实现
java基础解析系列(四)---LinkedHashMap的原理及LRU算法的实现 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析 ...
-
SSE图像算法优化系列十三:超高速BoxBlur算法的实现和优化(Opencv的速度的五倍)
在SSE图像算法优化系列五:超高速指数模糊算法的实现和优化(10000*10000在100ms左右实现) 一文中,我曾经说过优化后的ExpBlur比BoxBlur还要快,那个时候我比较的BoxBlur ...
-
详解Linux内核红黑树算法的实现
转自:https://blog.csdn.net/npy_lp/article/details/7420689 内核源码:linux-2.6.38.8.tar.bz2 关于二叉查找树的概念请参考博文& ...
-
详细MATLAB 中BP神经网络算法的实现
MATLAB 中BP神经网络算法的实现 BP神经网络算法提供了一种普遍并且实用的方法从样例中学习值为实数.离散值或者向量的函数,这里就简单介绍一下如何用MATLAB编程实现该算法. 具体步骤 这里 ...
随机推荐
-
css判断不同分辨率显示不同宽度布局实现自适应宽度
一.CSS DIV网页布局中当分辨率小于等于1024px(像素)时,DIV布局对象显示1000px宽度,当分辨率大于1024px时候显示1200px宽度等需求.使用CSS实现改变浏览器显示宽度从而实现 ...
-
Android学习笔记
1.问题:Error when loading the SDK:发现了以元素 'd:skin' 开头的无效内容 方法:删除了android-wear 用sdk\tools\lib下的de ...
-
Windows Phone Data Protection
To encrypt the PIN // Convert the PIN to a byte[]. byte[] PinByte = Encoding.UTF8.GetBytes(TBPin.Tex ...
-
函数fsp_alloc_seg_inode
从inode page中申请inode entry inode = fsp_alloc_seg_inode(space_header, mtr); /************************* ...
-
animation css3动画与CSS3 @keyframes担配使用创建往复平缓动画
通过 @keyframes 规则,您能够创建动画. 创建动画的原理是,将一套 CSS 样式逐渐变化为另一套样式. 在动画过程中,您能够多次改变这套 CSS 样式. 以百分比来规定改变发生的时间,或者通 ...
-
从零开始学安全(四)●Vmware CentOS 7 添加静态ip联网
一.虚拟网络编辑器配置 1.VMnet8设置(不需要改动) 2.NAT设置(不需要改动) 3.DHCP设置(CentOS IP地址段设置,不需要改动) 二.虚拟机设置(网络适配器选择NAT模式) 三. ...
-
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
学习Spring Boot 过程中遇到了下列这个问题 Description: Failed to configure a DataSource: 'url' attribute is not spe ...
-
Spring自动扫描无法扫描jar包中bean的解决方法(转)
转载自:http://www.jb51.net/article/116357.htm 在日常开发中往往会对公共的模块打包发布,然后调用公共包的内容.然而,最近对公司的公共模块进行整理发布后.sprin ...
-
【Linux笔记】ldconfig、ldd
一.ldconfig ldconfig是一个动态链接库管理命令,为了让动态链接库为系统所共享,还需运行动态链接库的管理命令--ldconfig. ldconfig 命令的用途,主要是在默认搜寻目录(/ ...
-
SQL group by的使用
①定义 "group by" 从字面上理解是根据“by"指定的规则对数据进行分组 ②简单示例 ③group by 中的select字段是受限制的 select指定的字段要 ...