今天看到了一篇关于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算法的实现的更多相关文章

  1. C++经典KMP算法的实现

    #include <iostream> #include <algorithm> #include <vector> #include <string> ...

  2. KMP算法的实现(Java语言描述)

    标签:it KMP算法是模式匹配专用算法. 它是在已知模式串的next或nextval数组的基础上执行的.如果不知道它们二者之一,就没法使用KMP算法,因此我们需要计算它们. KMP算法由两部分组成: ...

  3. 【字符串匹配】KMP算法和next数组的c/c++实现

    KMP算法基本思想有许多博客都写到了,写得也十分形象,不懂得可以参考下面的传送门,我就不解释基本思想了.本文主要给出KMP算法及next数组的计算方法(主要是很多网上的代码本人(相信应该是许多人吧)看 ...

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

    移动机器人智能的一个重要标志就是自主导航,而实现机器人自主导航有个基本要求--避障.之前简单介绍过Bug避障算法,但仅仅了解大致理论而不亲自动手实现一遍很难有深刻的印象,只能说似懂非懂.我不是天才,不 ...

  5. Canny边缘检测算法的实现

    图像边缘信息主要集中在高频段,通常说图像锐化或检测边缘,实质就是高频滤波.我们知道微分运算是求信号的变化率,具有加强高频分量的作用.在空域运算中来说,对图像的锐化就是计算微分.由于数字图像的离散信号, ...

  6. java基础解析系列(四)---LinkedHashMap的原理及LRU算法的实现

    java基础解析系列(四)---LinkedHashMap的原理及LRU算法的实现 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析 ...

  7. SSE图像算法优化系列十三:超高速BoxBlur算法的实现和优化(Opencv的速度的五倍)

    在SSE图像算法优化系列五:超高速指数模糊算法的实现和优化(10000*10000在100ms左右实现) 一文中,我曾经说过优化后的ExpBlur比BoxBlur还要快,那个时候我比较的BoxBlur ...

  8. 详解Linux内核红黑树算法的实现

    转自:https://blog.csdn.net/npy_lp/article/details/7420689 内核源码:linux-2.6.38.8.tar.bz2 关于二叉查找树的概念请参考博文& ...

  9. 详细MATLAB 中BP神经网络算法的实现

    MATLAB 中BP神经网络算法的实现 BP神经网络算法提供了一种普遍并且实用的方法从样例中学习值为实数.离散值或者向量的函数,这里就简单介绍一下如何用MATLAB编程实现该算法. 具体步骤   这里 ...

随机推荐

  1. ASP.NET基础之HttpHandler学习

    ASP.NET基础之HttpHandler学习 经过前两篇[ASP.NET基础之HttpModule学习]和[ASP.NET基础之HttpContext学习]文章的学习我们对ASP.NET的基础内容有 ...

  2. 【详细贴】Ubuntu Linode搭建海外策略路由VPN IPSec+L2TP(一)

    对于码农来说,Google上搜索,stackoverflow上提问,twitter上交流,这样的国际化开放平台才是码农成长的空间.但是,目前遇到的一些现实的困难,无可避免的带来一些麻烦,不过这难不倒我 ...

  3. Eclipse代码自动提示设置

    以前百度过如何设置Eclipse代码自动提示,但是本人记性不好,所以把这个方法写成一篇日志,这样以后就不用百度了,直接看自己的博客就是了,而且还增加了自己博客的点击量.以下是从各个地方看到总结的方法: ...

  4. iOS-王云鹤 APP首次启动显示用户指导

    这个功能的重点就是在如何判断应用是第一次启动的. 其实很简单 我们只需要在一个类里面写好用户引导页面  基本上都是使用UIScrollView 来实现, 新建一个继承于UIViewController ...

  5. centos 6.4 x64安装bugfree

    第一步:下载xampp-linux-1.8.1.tar.gz [root@SVNMANAGER ~]# tar -zxvf xampp-linux-1.8.1.tar.gz -C /opt [root ...

  6. javascript深入之location对象和history对象

    浏览器的location 和history对象: 一.location对象: 1>location.reload() 相当于按浏览器上的“刷新”(IE)或“Reload”(Netscape)键. ...

  7. 内核操作系统Linux内核变迁杂谈——感知市场的力量

    本篇文章个人在青岛游玩的时候突然想到的...今天就有想写几篇关于内核操作系统的博客,所以回家到以后就奋笔疾书的写出来发表了 Jack:什么是操作系统? 我:你买了一台笔记本,然后把整块硬盘彻底格式化, ...

  8. JS —— 数组与字符串方法

    数组 1. 基本方法  1)Array.prototype.unshift(item1,item2,item3...) 描述: 在数组的前面添加元素,一次可以传入多个参数. 注意:元素会根据当前传入的 ...

  9. oracle表空间表分区详解及oracle表分区查询使用方法(转+整理)

    欢迎和大家交流技术相关问题: 邮箱: jiangxinnju@163.com 博客园地址: http://www.cnblogs.com/jiangxinnju GitHub地址: https://g ...

  10. VS 使用技巧

    1.按下alt键,可以做到竖向选择 2.