ImageVerifierCode 换一换
格式:DOCX , 页数:10 ,大小:84.15KB ,
资源ID:25057185      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/25057185.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(kmp算法讲解.docx)为本站会员(b****9)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

kmp算法讲解.docx

1、kmp算法讲解本文介绍了字符串匹配算法中的BF算法和KMP算法。本文中KMP算法介绍部分是关于KMP算法相关文章中最简洁的一篇文章之一。下一篇将继续介绍Horspool算法和BM算法。现在我们用的大部分软件都含有查找/替换的功能,要完成查找替换功能就需要用到字符串匹配算法。字符串匹配的算法有很多,最著名的字符串匹配算法有:KMP算法,Boyer-Moore(BM)算法。如果要我们自己去实现字符串匹配功能,我们会怎样去做呢?当然,我们最容易想到的方法就是人们常说的蛮力匹配法。术语:模式串:即你要查找或替换的字符串。源串/匹配串:你要从哪里查找或者替换哪里的字符串。比如你想在test.txt中查找

2、是否含有linux-code这个单词,那么模式串即为linux-code,源串/匹配串即为test.txt内的字符串。现在我们就来谈谈如何从源串中匹配模式串吧!算法一:Brute Force算法,即蛮力匹配法。判断一个字符串是否为另一个字符串的子串,最简单的方法就是将模式串与源串一个个字符比较,如果不相等则将模式串后移一位,继续比较。如此,直到子串完全匹配或者到达源字符串的末尾。代码也很简洁,几行就搞定。当然,其效率也是很低下的。intbf_match(char*src,char*pattern)if(src=NULL| pattern =NULL) return 0;intlen1=strl

3、en(src);intlen2=strlen(pattern);inti,j;for(i=0;ilen1;+i)for(j=0;jlen2;+j) if(srci+j!=patternj)break;if(j=len2-1)reurni; return-1; /没有匹配成功,返回-1当然还有很多蛮力算法的改进算法,我们这里不做进一步讨论。算法二:KMP算法曾经,KMP算法很让人头痛!是三个牛X哄哄的人提出来的。因此,我们第一眼看去,该算法并不好理解。关于KMP算法的阮一峰的这篇文章,是我看到过的写得最精炼简洁的一篇。原文摘录如下(原作者:阮一峰)。来听听,KMP算法是怎么实现的吧!举例来说,有

4、一个字符串BBC ABCDAB ABCDABCDABDE,我想知道,里面是否包含另一个字符串ABCDABD?1.首先,字符串BBC ABCDAB ABCDABCDABDE的第一个字符与搜索词ABCDABD的第一个字符,进行比较。因为B与A不匹配,所以搜索词后移一位。2.因为B与A不匹配,搜索词再往后移。3.就这样,直到字符串有一个字符,与搜索词的第一个字符相同为止。4.接着比较字符串和搜索词的下一个字符,还是相同。5.直到字符串有一个字符,与搜索词对应的字符不相同为止。6.这时,最自然的反应是,将搜索词整个后移一位,再从头逐个比较。这样做虽然可行,但是效率很差,因为你要把搜索位置移到已经比较过

5、的位置,重比一遍。7.一个基本事实是,当空格与D不匹配时,你其实知道前面六个字符是ABCDAB。KMP算法的想法是,设法利用这个已知信息,不要把搜索位置移回已经比较过的位置,继续把它向后移,这样就提高了效率。8.怎么做到这一点呢?可以针对搜索词,算出一张部分匹配表(Partial Match Table)。这张表是如何产生的,后面再介绍,这里只要会用就可以了。9.已知空格与D不匹配时,前面六个字符ABCDAB是匹配的。查表可知,最后一个匹配字符B对应的部分匹配值为2,因此按照下面的公式算出向后移动的位数:移动位数 = 已匹配的字符数 - 对应的部分匹配值因为 6 - 2 等于4,所以将搜索词向

6、后移动4位。10.因为空格与不匹配,搜索词还要继续往后移。这时,已匹配的字符数为2(AB),对应的部分匹配值为0。所以,移动位数 = 2 - 0,结果为 2,于是将搜索词向后移2位。11.因为空格与A不匹配,继续后移一位。12.逐位比较,直到发现C与D不匹配。于是,移动位数 = 6 - 2,继续将搜索词向后移动4位。13.逐位比较,直到搜索词的最后一位,发现完全匹配,于是搜索完成。如果还要继续搜索(即找出全部匹配),移动位数 = 7 - 0,再将搜索词向后移动7位,这里就不再重复了。14.下面介绍部分匹配表是如何产生的。首先,要了解两个概念:前缀和后缀。 前缀指除了最后一个字符以外,一个字符串

7、的全部头部组合;后缀指除了第一个字符以外,一个字符串的全部尾部组合。15.部分匹配值就是前缀和后缀的最长的共有元素的长度。以ABCDABD为例: A的前缀和后缀都为空集,共有元素的长度为0; AB的前缀为A,后缀为B,共有元素的长度为0; ABC的前缀为A, AB,后缀为BC, C,共有元素的长度0; ABCD的前缀为A, AB, ABC,后缀为BCD, CD, D,共有元素的长度为0; ABCDA的前缀为A, AB, ABC, ABCD,后缀为BCDA, CDA, DA, A,共有元素为A,长度为1; ABCDAB的前缀为A, AB, ABC, ABCD, ABCDA,后缀为BCDAB, C

8、DAB, DAB, AB, B,共有元素为AB,长度为2; ABCDABD的前缀为A, AB, ABC, ABCD, ABCDA, ABCDAB,后缀为BCDABD, CDABD, DABD, ABD, BD, D,共有元素的长度为0。16.部分匹配的实质是,有时候,字符串头部和尾部会有重复。比如,ABCDAB之中有两个AB,那么它的部分匹配值就是2(AB的长度)。搜索词移动的时候,第一个AB向后移动4位(字符串长度-部分匹配值),就可以来到第二个AB的位置。从上面的讲解可以看出,KMP算法的核心是如何得到在字符失配时的移动步长。也就是如何得到部分匹配表。OK,现在KMP算法基本介绍完了。来二

9、两代码吧!KMP算法的一个关键部分是得到部分匹配表。那么部分匹配表如何得到呢?上文已经有详细的介绍。部分匹配值就是前缀和后缀的最长的共有元素的长度。以ABCDABD为例: A的前缀和后缀都为空集,共有元素的长度为0; AB的前缀为A,后缀为B,共有元素的长度为0; ABC的前缀为A, AB,后缀为BC, C,共有元素的长度0; ABCD的前缀为A, AB, ABC,后缀为BCD, CD, D,共有元素的长度为0; ABCDA的前缀为A, AB, ABC, ABCD,后缀为BCDA, CDA, DA, A,共有元素为A,长度为1; ABCDAB的前缀为A, AB, ABC, ABCD, ABCD

10、A,后缀为BCDAB, CDAB, DAB, AB, B,共有元素为AB,长度为2; ABCDABD的前缀为A, AB, ABC, ABCD, ABCDA, ABCDAB,后缀为BCDABD, CDABD, DABD, ABD, BD, D,共有元素的长度为0。据此,我们可以编码如下:/返回值为一个指针。其指向的地址块连续存放了部分匹配表。int* get_pmt(char* pattern)if(pattern=NULL)returnNULL;intlen=strlen(pattern);int* ppmt=(int*)malloc(len+1)*sizeof(int);/分配内存,用于存放

11、部分匹配表。 memset(ppmt,0,sizeof(len+1)*sizeof(int);/将分配的内存初始化为0inti,j,k;for(i=1;ilen;+i)for(j=0;ji;+j)for(k=0;k=ppmti) ppmti=k+1; returnppmt;好了,有了get_pmt函数后,我们就可以轻松的写出kmp算法了。全部代码如下,如果你看不明白,那去仔细看看正文吧。#include #include #include int* get_pmt(char* pattern)if(pattern=NULL)returnNULL;intlen=strlen(pattern);i

12、nt* ppmt=(int*)malloc(len+1)*sizeof(int);/分配内存,用于存放部分匹配表。 memset(ppmt,0,sizeof(len+1)*sizeof(int);/将分配的内存初始化为0inti,j,k;for(i=1;ilen;+i)for(j=0;ji;+j)for(k=0;k=ppmti) ppmti=k+1; returnppmt;intkmp_match(char*src,char*pattern)if(src=NULL| pattern=NULL)return-1;intlen1=strlen(src);intlen2=strlen(pattern

13、);int*pmt=get_pmt(pattern);printf(src len is:%dn pattern len is:%dn,len1,len2);inti,j;for(i=0;ilen1-len2;)for(j=0;j1 ? (j-pmtj):1;printf(i is %dn,i);/为了观察中间结果 break; if(j=len2-1)if(pmt)free(pmt);returni; if(pmt) free(pmt);return-1;intmain()charsrc32=teslinuxlitforlinuxlinuetestfor;charpattern10=linuxlinu;printf(kmp_match result:%dn,kmp_match(src,pattern);当然,上述代码并不是最优的代码,get_pmt函数的实现可以进行进一步优化,这里就不涉及了。作者:JJDiaries(阿呆) 微信公众号:linux-code

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1