KMP算法的实现
今天看到了一篇关于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编程实现该算法. 具体步骤 这里 ...
随机推荐
- springMVC3学习(十一)--文件上传CommonsMultipartFile
使用springMVC提供的CommonsMultipartFile类进行读取文件 需要用到上传文件的两个jar包 commons-logging.jar.commons-io-xxx.jar 1.在 ...
- 用Winrar批量解压缩有密码文件方法,只需输入一次密码
老王上传的文件多是RAR压缩格式的, 每个系列下载完,都20多集,解压缩的时候要一个一个的输入密码,太浪费时间. 1) 把下载的需要解压缩的文件统一放到一个文件夹下. 2) 启动winrar程序 (从 ...
- synchronized和volatile的使用
synchronized和volatile的使用 一步一步掌握线程机制(三)---synchronized和volatile的使用 现在开始进入线程编程中最重要的话题---数据同步,它是线程编程的核心 ...
- Using CrunchBase API
Let us have fun with CrunchBase API. What can CrunchBase API give us? They said: https://developer.c ...
- PostgreSQL9.1 with PostGIS 2.1.4 for mapping coordinates on linux/ubuntu 已经打包成deb 可下载
For location based service, I try to use postgresql with postgis. You can download postgis from here ...
- 记一次修复被篡改的IE首页
今天开电脑,打开IE发现首页被篡改为http://www.you2000.cn/,下意识是恶意插件造成的,可是为什么金山卫士没发现呢(我电脑上只装了一个金山卫士)?我锁定首页的啊... 只好手动运行金 ...
- 理解git分支-远程分支
远程分支 远程引用是对远程仓库的引用(指针),包括分支.标签等等. 你可以通过 git ls-remote (remote)来显式地获得远程引用的完整列表,或者通过 git remote show ( ...
- winform总结4> 工欲善其事,必先利其器之xml校验
@echo 根据xml自动生成xml @echo 当前路径包含空格会导致执行失败 ::pause @echo off set path=%~dp0 for /r %path% %%i in (*.xm ...
- DIV 实现可拖拽 功能(留档)
//可拖拽 功能 $.fn.extend({ //用法:$(element).jqDrag(); //element需要具备定位属性,需要手动调整层叠样式,这里只是修改鼠标拖动效果 ...
- OpenCV示例学习笔记(1)-contours2.cpp-通过findContours 函数实现轮廓提取
这个系列的目的是通过对OpenCV示例,进一步了解OpenCV函数的使用,不涉及具体原理. 示例代码地址:http://docs.opencv.org/3.0.0/examples.html(安装op ...