当前位置: 首页 > news >正文

我的KMP实现

前言

之前在搞ACM的时候了解过KMP,可是最近发现细节记不清楚了,索性重新看一遍这些基础的算法,我们先来看一下定义:“KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)”。这里对KMP的定义是字符串匹配算法,当然这个算法不仅仅是用来处理字符串的,你可以应用于查找子序列的各种问题中。

KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息,将时间复杂度从暴力匹配的O(mn)优化成了O(m+n)。现在我处于的状态是一个知其然也知其所以然的状态,也就是说知道KMP算法为什么要这样做,但是我确实没办法给第二个人讲得清清楚楚,简单来说还是功力不够,等我再练练一定给大家简单的讲一下。

内容

既然看了一天的算法总得有点收获,所以今天我决定根据自己的理解来实现以下KMP算法,代码如下,有什么不正确的地方欢迎大家指出来

  • KMP使用实例

#include 
  
   
#include 
   
    
#include 
    
     


bool getNext(const char* pPattern, int* pNext, int nSize)
{
	if (NULL == pPattern)
		return false;

	const int nPatternLen = strlen(pPattern);
	if (nPatternLen >= nSize)
		return false;

	// 初始化第一个元素的字符串的前缀和后缀公共部分的最大长度
	pNext[0] = pNext[1] = 0;

	// 已经匹配的元素个数
	int nMatchCount = 0;
	for (int nIndex = 1; nIndex < nPatternLen; ++nIndex)
	{

		// 遇到不匹配的元素递归处理找到最长的匹配子串
		while (nMatchCount > 0 && pPattern[nMatchCount] != pPattern[nIndex])
			nMatchCount = pNext[nMatchCount];

		if (pPattern[nMatchCount] == pPattern[nIndex])
			++nMatchCount;

		pNext[nIndex + 1] = nMatchCount;

	}

	return true;
}

// 返回找到的位置索引,未找到范返回-1
int findMatch(const char* pSrcContent, const char* pPattern)
{
	if (NULL != pSrcContent && NULL == pPattern)
		return -1;

	int nPatternLen = strlen(pPattern);
	int nSrcContentLen = strlen(pSrcContent);
	if (nSrcContentLen < nPatternLen)
		return -1;

	int* pNext = new int[nPatternLen + 1];
	if (NULL == pNext)
		return -1;

	if (!getNext(pPattern, pNext, nPatternLen + 1))
	{
		delete pNext;
		return -1;
	}

	// 匹配的个数
	int nMatchCount = 0;
	for (int nIndex = 0; nIndex < nSrcContentLen; ++nIndex)
	{
		// 发现不匹配
		while (nMatchCount > 0 && pSrcContent[nIndex] != pPattern[nMatchCount])
			nMatchCount = pNext[nMatchCount];

		if (pSrcContent[nIndex] == pPattern[nMatchCount])
			++nMatchCount;

		if (nPatternLen == nMatchCount)
		{
			return nIndex + 1 - nPatternLen;
		}
	}

	return -1;
}


int main()
{
	char szA[] = "aaaasdfhasidfahakfambfjawefjghfka";
	char szB[] = "fam";

	int nRet = findMatch(szA, szB);

	if (nRet < 0)
	{
		printf("find %s in %s postion : not find\n", szB, szA);
	}
	else
	{
		printf("find %s in %s postion : %d\n",szB, szA, nRet);
	}

	system("pause");
	return 0;
}
    
   
  

  • 运行结果

find fam in aaaasdfhasidfahakfambfjawefjghfka postion : 17

总结

  • 这个算法最主要的就是实现next函数,也就是找到模板串中每个字符的前串的前缀和后缀公共部分的最大长度。
  • 在查找过程中要注意算法含义的转化,其中所说的模板串向后移动在代码中的实现看起来并不像移动,但含义是相同的。
  • 注意计算next函数和查找过程中不断分割子串的操作,我个人感觉这句代码while (nMatchCount > 0 && pPattern[nMatchCount] != pPattern[nIndex]) nMatchCount = pNext[nMatchCount];是KMP算法中最精妙的部分了,学习算法时要注意这句的理解。

另注

我决定在此处先画一条分割线,关于代码实现的细节和主要思想,我还没有想好怎么表达,待我组织清楚后,一定要静下心来写一写。。。



相关文章:

  • SVN:Update item to this version和Revert to this version区别
  • CSDN博客:使用Markdown编辑器使图片居中显示
  • UE4项目运行时显示鼠标指针
  • UE4引擎中类的命名规则
  • 排序算法系列之(零)——排序初体验
  • 光棍节程序员闯关秀-解密
  • Mysql批量删除数据库
  • UE4中的反射机制
  • 排序算法系列之(一)——选择排序清新脱俗的一面
  • C++11(一):在类的定义时初始化非静态变量
  • C++11(二):lamda表达式
  • 可能错误使用了‘offsetof’宏
  • 警告:对 NULL 对象非静态数据成员‘XXX::xxx’的访问无效
  • git tag常用操作
  • error: SEH exception with code 0xc0000005 thrown in the test
  • 《深入 React 技术栈》
  • 【刷算法】从上往下打印二叉树
  • ➹使用webpack配置多页面应用(MPA)
  • Codepen 每日精选(2018-3-25)
  • C语言笔记(第一章:C语言编程)
  • ES2017异步函数现已正式可用
  • java中的hashCode
  • Linux学习笔记6-使用fdisk进行磁盘管理
  • Median of Two Sorted Arrays
  • NSTimer学习笔记
  • php中curl和soap方式请求服务超时问题
  • python大佬养成计划----difflib模块
  • python学习笔记 - ThreadLocal
  • spring boot下thymeleaf全局静态变量配置
  • Sublime Text 2/3 绑定Eclipse快捷键
  • WordPress 获取当前文章下的所有附件/获取指定ID文章的附件(图片、文件、视频)...
  • 第十八天-企业应用架构模式-基本模式
  • 关于字符编码你应该知道的事情
  • 基于阿里云移动推送的移动应用推送模式最佳实践
  • 将回调地狱按在地上摩擦的Promise
  • 前端存储 - localStorage
  • 前端路由实现-history
  • 首页查询功能的一次实现过程
  • 问题之ssh中Host key verification failed的解决
  • 小而合理的前端理论:rscss和rsjs
  • 组复制官方翻译九、Group Replication Technical Details
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • #ifdef 的技巧用法
  • #WEB前端(HTML属性)
  • $var=htmlencode(“‘);alert(‘2“); 的个人理解
  • (13)Latex:基于ΤΕΧ的自动排版系统——写论文必备
  • (33)STM32——485实验笔记
  • (java)关于Thread的挂起和恢复
  • (rabbitmq的高级特性)消息可靠性
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (附源码)springboot建达集团公司平台 毕业设计 141538
  • (附源码)springboot青少年公共卫生教育平台 毕业设计 643214
  • (入门自用)--C++--抽象类--多态原理--虚表--1020
  • .net 4.0 A potentially dangerous Request.Form value was detected from the client 的解决方案
  • .net mvc 获取url中controller和action