搜档网
当前位置:搜档网 › KMP字符串模式匹配算法解释

KMP字符串模式匹配算法解释

KMP字符串模式匹配算法解释
KMP字符串模式匹配算法解释

个人觉得这篇文章是网上的介绍有关KMP算法更让人容易理解的文章了,确实说得很“详细”,耐心地把它看完肯定会有所收获的~~,另外有关模式函数值next[i]确实有很多版本啊,在另外一些面向对象的算法描述书中也有失效函数f(j)的说法,其实是一个意思,即next[j]=f(j-1)+1,不过还是next[j]这种表示法好理解啊:

KMP字符串模式匹配详解

KMP字符串模式匹配通俗点说就是一种在一个字符串中定位另一个串的高效算法。简单匹配算法的时间复杂度为O(m*n);KMP匹配算法。可以证明它的时间复杂度为O(m+n).。

一.简单匹配算法

先来看一个简单匹配算法的函数:

int Index_BF ( char S [ ], char T [ ], int pos )

{

/* 若串S 中从第pos(S 的下标0≤pos

起存在和串T 相同的子串,则称匹配成功,返回第一个

这样的子串在串S 中的下标,否则返回-1 */

int i = pos, j = 0;

while ( S[i+j] != '\0'&& T[j] != '\0')

if ( S[i+j] == T[j] )

j ++; // 继续比较后一字符

else

{

i ++; j = 0; // 重新开始新的一轮匹配

}

if ( T[j] == '\0')

return i; // 匹配成功返回下标

else

return -1; // 串S中(第pos个字符起)不存在和串T相同的子串

} // Index_BF

此算法的思想是直截了当的:将主串S中某个位置i起始的子串和模式串T相

比较。即从j=0 起比较S[i+j] 与T[j],若相等,则在主串S 中存在以i 为起始位置匹配成功的可能性,继续往后比较( j逐步增1 ),直至与T串中最后一个字符相等为止,否则改从S串的下一个字符起重新开始进行下一轮的"匹配",即将串T向后滑动一位,即i 增1,而j 退回至0,重新开始新一轮的匹配。

例如:在串S=”abcabcabdabba”中查找T=” abcabd”(我们可以假设从下标0开始):先是比较S[0]和T[0]是否相等,然后比较S[1] 和T[1]是否相等…我们发现一直比较到S[5] 和T[5]才不等。如图:

当这样一个失配发生时,T下标必须回溯到开始,S下标回溯的长度与T 相同,然后S下标增1,然后再次比较。如图:

这次立刻发生了失配,T下标又回溯到开始,S下标增1,然后再次比较。如图:

这次立刻发生了失配,T下标又回溯到开始,S下标增1,然后再次比较。如图:

又一次发生了失配,所以T下标又回溯到开始,S下标增1,然后再次比较。这次T中的所有字符都和S中相应的字符匹配了。函数返回T在S中的起始下标3。如图:

二. KMP匹配算法

还是相同的例子,在S=”abcabcabdabba”中查找T=”abcabd”,如果使用KMP匹配算法,当第一次搜索到S[5] 和T[5]不等后,S下标不是回溯到1,T下标也不是回溯到开始,而是根据T中T[5]==’d’的模式函数值

(next[5]=2,为什么?后面讲),直接比较S[5] 和T[2]是否相等,因为相等,S和T的下标同时增加;因为又相等,S和T的下标又同时增加。。。最终在S

中找到了T。如图:

KMP匹配算法和简单匹配算法效率比较,一个极端的例子是:

在S=“AAAAAA…AAB“(100个A)中查找T=”AAAAAAAAAB”, 简单匹配算法每次都是比较到T的结尾,发现字符不同,然后T的下标回溯到开始,S的下标也要回溯相同长度后增1,继续比较。如果使用KMP匹配算法,就不必回溯.

对于一般文稿中串的匹配,简单匹配算法的时间复杂度可降为O (m+n),因此在多数的实际应用场合下被应用。

KMP算法的核心思想是利用已经得到的部分匹配信息来进行后面的匹配

过程。看前面的例子。为什么T[5]==’d’的模式函数值等于2(next[5]=2),其

实这个2表示T[5]==’d’的前面有2个字符和开始的两个字符相同,且T[5]==’d’不等于开始的两个字符之后的第三个字符(T[2]=’c’).如图:

也就是说,如果开始的两个字符之后的第三个字符也为’d’,那么,尽管T[5]==’d’的前面有2个字符和开始的两个字符相同,T[5]==’d’的模式函数值也不为2,而是为0。

前面我说:在S=”abcabcabdabba”中查找T=”abcabd”,如果使用KMP匹配算法,当第一次搜索到S[5] 和T[5]不等后,S下标不是回溯到1,T 下标也不是回溯到开始,而是根据T中T[5]==’d’的模式函数值,直接比较S[5] 和T[2]是否相等。。。为什么可以这样?

刚才我又说:“(next[5]=2),其实这个2表示T[5]==’d’的前面有2个字符和开始的两个字符相同”。请看图:因为,S[4] ==T[4],S[3] ==T[3],根据next[5]=2,有T[3]==T[0],T[4] ==T[1],所以S[3]==T[0],S[4] ==T[1](两对相当于间接比较过了),因此,接下来比较S[5] 和T[2]是否相等。。。

有人可能会问:S[3]和T[0],S[4] 和T[1]是根据next[5]=2间接比较相等,那S[1]和T[0],S[2] 和T[0]之间又是怎么跳过,可以不比较呢?因为

S[0]=T[0],S[1]=T[1],S[2]=T[2],而T[0] != T[1], T[1] != T[2],==> S[0] != S[1],S[1] != S[2],所以S[1] != T[0],S[2] != T[0]. 还是从理论上间接比较了。

有人疑问又来了,你分析的是不是特殊轻况啊。

假设S不变,在S中搜索T=“abaabd”呢?答:这种情况,当比较到S[2]和T[2]时,发现不等,就去看next[2]的值,next[2]=-1,意思是S[2]已经和T[0] 间接比较过了,不相等,接下来去比较S[3]和T[0]吧。

++j; ++k;

if (T[j]!=T[k])

next[j] = k;

else

next[j] = next[k];

}// if

else

k = next[k];

}// while

////这里是我加的显示部分

// for(int i=0;i

//{

// cout<

//}

//cout<

}// get_nextval

另一种写法,也差不多。

void getNext(const char* pattern,int next[]) {

next[0]= -1;

int k=-1,j=0;

while(pattern[j] != '\0')

{

if(k!= -1 && pattern[k]!= pattern[j] )

k=next[k];

++j;++k;

if(pattern[k]== pattern[j])

next[j]=next[k];

else

next[j]=k;

}

////这里是我加的显示部分

// for(int i=0;i

//{

// cout<

//}

//cout<

}

下面是KMP模式匹配程序,各位可以用他验证。记得加入上面的函数

#include

#include

int KMP(const char *Text,const char* Pattern) //const 表示函数内部不会改变这个参数的值。

{

if( !Text||!Pattern|| Pattern[0]=='\0' || Text[0]=='\0' )//

return -1;//空指针或空串,返回-1。

int len=0;

const char * c=Pattern;

while(*c++!='\0')//移动指针比移动下标快。

{

++len;//字符串长度。

}

int *next=new int[len+1];

get_nextval(Pattern,next);//求Pattern的next函数值

int index=0,i=0,j=0;

while(Text[i]!='\0' && Pattern[j]!='\0' )

{

if(Text[i]== Pattern[j])

{

++i;// 继续比较后继字符

++j;

}

else

{

index += j-next[j];

if(next[j]!=-1)

j=next[j];// 模式串向右移动

else

{

j=0;

++i;

}

}

}//while

delete []next;

if(Pattern[j]=='\0')

return index;// 匹配成功

else

return -1;

}

int main()//abCabCad

{

char* text="bababCabCadcaabcaababcbaaaabaaacababcaabc";

char*pattern="adCadCad";

//getNext(pattern,n);

//get_nextval(pattern,n);

cout<

return 0;

}

五.其他表示模式值的方法

上面那种串的模式值表示方法是最优秀的表示方法,从串的模式值我们可以得到很多信息,以下称为第一种表示方法。第二种表示方法,虽然也定义next[0]= -1,但后面绝不会出现-1,除了next[0],其他模式值next[j]=k(0≤k

next[j]=k(0≤k

从这里我们可以看到:串的模式值第一种表示方法能表示更多的信息,第二种表示方法更单纯,不容易搞错。当然,用第一种表示方法写出的模式匹配函数效率更高。比如说,在串S=“adCadCBdadCadCad 9876543”中匹配串

T=“adCadCad”, 用第一种表示方法写出的模式匹配函数,当比较到S[6] != T[6] 时,取next[6]= -1(表三),它可以表示这样许多信息:

S[3]S[4]S[5]==T[3]T[4]T[5]==T[0]T[1]T[2],而S[6] != T[6],

T[6]==T[3]==T[0],所以S[6] != T[0],接下来比较S[7]和T[0]吧。如果用第二种表示方法写出的模式匹配函数,当比较到S[6] != T[6] 时,取next[6]= 3(表三),它只能表示:S[3]S[4]S[5]== T[3]T[4]T[5]==T[0]T[1]T[2],但不能确定T[6]与T[3]相不相等,所以,接下来比较S[6]和T[3];又不相等,取next[3]= 0,它表示S[3]S[4]S[5]== T[0]T[1]T[2],但不会确定T[3]与T[0]相不相等,即S[6]和T[0] 相不相等,所以接下来比较S[6]和T[0],确定它们不相等,然后才会比较S[7]和T[0]。是不是比用第一种表示方法写出的模式匹配函数多绕了几个弯。

为什么,在讲明第一种表示方法后,还要讲没有第一种表示方法好的第二种表示方法?原因是:最开始,我看严蔚敏的一个讲座,她给出的模式值表示方法是我这里的第二种表示方法,如图:

她说:“next 函数值的含义是:当出现S[i] !=T[j]时,下一次的比较应该在S[i]和T[next[j]] 之间进行。”虽简洁,但不明了,反复几遍也没明白为什么。而她给出的算法求出的模式值是我这里说的第一种表示方法next值,就是前面的get_nextval()函数。匹配算法也是有瑕疵的。于是我在这里发帖说她错了:https://www.sodocs.net/doc/5c342082.html,/Expert/topic/4413/4413398.xml?temp=.202724 6

现在看来,她没有错,不过有张冠李戴之嫌。我不知道,是否有人第一次学到这里,不参考其他资料和明白人讲解的情况下,就能搞懂这个算法(我的意思是不仅是算法的大致思想,而是为什么定义和例子中next[j]=k(0≤k

书归正传,下面给出我写的求第二种表示方法表示的模式值的函数,为了从S的任何位置开始匹配T,“当出现S[i] !=T[j]时,下一次的比较应该在S[i]和

T[next[j]] 之间进行。”定义next[0]=0 。

v oid myget_nextval(const char *T, int next[])

{

// 求模式串T的next函数值(第二种表示方法)并存入数组next。

int j = 1, k = 0;

next[0] = 0;

while ( T[j] != '\0' )

{

if(T[j] == T[k])

{

next[j] = k;

++j; ++k;

}

else if(T[j] != T[0])

{

next[j] = k;

++j;

k=0;

}

else

{

next[j] = k;

++j;

k=1;

}

}//while

for(int i=0;i

{

cout<

}

cout<

}// myget_nextval

下面是模式值使用第二种表示方法的匹配函数(next[0]=0)

int my_KMP(char *S, char *T, int pos)

{

int i = pos, j = 0;//pos(S 的下标0≤pos

while ( S[i] != '\0' && T[j] != '\0' )

{

if (S[i] == T[j] )

{

++i;

++j; // 继续比较后继字符

}

else // a b a b c a a b c

// 0 0 0 1 2 0 1 1 2

{ //-1 0 -1 0 2 -1 1 0 2

i++;

j = next[j]; /*当出现S[i] !=T[j]时,

下一次的比较应该在S[i]和T[next[j]] 之间进行。要求next[0]=0。

在这两个简单示范函数间使用全局数组next[]传值。*/

}

}//while

if ( T[j] == '\0' )

return (i-j); // 匹配成功

else

return -1;

} // my_KMP

六.后话--KMP的历史

[这段话是抄的]

Cook于1970年证明的一个理论得到,任何一个可以使用被称为下推自动机的计算机抽象模型来解决的问题,也可以使用一个实际的计算机(更精确的说,使用一个随机存取机)在与问题规模对应的时间内解决。特别地,这个理论暗示存在着一个算法可以在大约m+n的时间内解决模式匹配问题,这里m和n分别是存储文本和模式串数组的最大索引。Knuth 和Pratt努力地重建了Cook的证明,由此创建了这个模式匹配算法。大概是同一时间,Morris在考虑设计一个文本编辑器的实际问题的过程中创建了差不多是同样的算法。这里可以看到并不

是所有的算法都是“灵光一现”中被发现的,而理论化的计算机科学确实在一些时候会应用到实际的应用中。

字符串的模式匹配算法

在前面的图文中,我们讲了“串”这种数据结构,其中有求“子串在主串中的位置”(字符串的模式匹配)这样的算法。解决这类问题,通常我们的方法是枚举从A串(主串)的什么位置起开始与B串(子串)匹配,然后验证是否匹配。假设A串长度为n,B串长度为m,那么这种方法的复杂度是O(m*n)的。虽然很多时候复杂度达不到m*n(验证时只看头一两个字母就发现不匹配了),但是我们有许多“最坏情况”,比如: A=“aaaaaaaaaaaaaaaaaaaaaaaaab”,B=“aaaaaaaab”。 大家可以忍受朴素模式匹配算法(前缀暴力匹配算法)的低效吗?也许可以,也许无所谓。 有三位前辈D.E.Knuth、J.H.Morris、V.R.Pratt发表一个模式匹配算法,最坏情况下是O(m+n),可以大大避免重复遍历的情况,我们把它称之为克努特-莫里斯-普拉特算法,简称KMP算法。 假如,A=“abababaababacb”,B=“ababacb”,我们来看看KMP是怎样工作的。我们用两个指针i和j分别表示,。也就是说,i是不断增加的,随着i 的增加j相应地变化,且j满足以A[i]结尾的长度为j的字符串正好匹配B串的前j个字符(j当然越大越好),现在需要检验A[i+1]和B[j+1]的关系。 例子: S=“abcdefgab” T=“abcdex” 对于要匹配的子串T来说,“abcdex”首字符“a”与后面的串“bcdex”中任意一个字符都不相等。也就是说,既然“a”不与自己后面的子串中任何一字符相等,那么对于主串S来说,前5位字符分别相等,意味着子串T的首字符“a”不可能与S串的第2到第5位的字符相等。朴素算法步骤2,3,4,5的判断都是多余,下次的起始位置就是第6个字符。 例子: S=“abcabcabc” T=“abcabx”

模式匹配的KMP算法详解

模式匹配的KMP算法详解 模式匹配的KMP算法详解 这种由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现的改进的模式匹配算法简称为KMP算法。大概学过信息学的都知道,是个比较难理解的算法,今天特把它搞个彻彻底底明明白白。 注意到这是一个改进的算法,所以有必要把原来的模式匹配算法拿出来,其实理解的关键就在这里,一般的匹配算法: int Index(String S,String T,int pos)//参考《数据结构》中的程序 { i=pos;j=1;//这里的串的第1个元素下标是1 while(i<=S.Length && j<=T.Length) { if(S[i]==T[j]){++i;++j;} else{i=i-j+2;j=1;}//**************(1) } if(j>T.Length) return i-T.Length;//匹配成功 else return 0; } 匹配的过程非常清晰,关键是当‘失配’的时候程序是如何处理的?回溯,没错,注意到(1)句,为什么要回溯,看下面的例子: S:aaaaabababcaaa T:ababc aaaaabababcaaa ababc.(.表示前一个已经失配) 回溯的结果就是 aaaaabababcaaa a.(babc) 如果不回溯就是 aaaaabababcaaa aba.bc 这样就漏了一个可能匹配成功的情况 aaaaabababcaaa ababc 为什么会发生这样的情况?这是由T串本身的性质决定的,是因为T串本身有前后'部分匹配'的性质。如果T为abcdef这样的,大没有回溯的必要。

串的模式匹配算法实验报告

竭诚为您提供优质文档/双击可除串的模式匹配算法实验报告 篇一:串的模式匹配算法 串的匹配算法——bruteForce(bF)算法 匹配模式的定义 设有主串s和子串T,子串T的定位就是要在主串s中找到一个与子串T相等的子串。通常把主串s称为目标串,把子串T称为模式串,因此定位也称作模式匹配。模式匹配成功是指在目标串s中找到一个模式串T;不成功则指目标串s中不存在模式串T。bF算法 brute-Force算法简称为bF算法,其基本思路是:从目标串s的第一个字符开始和模式串T中的第一个字符比较,若相等,则继续逐个比较后续的字符;否则从目标串s的第二个字符开始重新与模式串T的第一个字符进行比较。以此类推,若从模式串T的第i个字符开始,每个字符依次和目标串s中的对应字符相等,则匹配成功,该算法返回i;否则,匹配失败,算法返回0。 实现代码如下:

/*返回子串T在主串s中第pos个字符之后的位置。若不存在,则函数返回值为0./*T非空。 intindex(strings,stringT,intpos) { inti=pos;//用于主串s中当前位置下标,若pos不为1则从pos位置开始匹配intj=1;//j用于子串T中当前位置下标值while(i j=1; } if(j>T[0]) returni-T[0]; else return0; } } bF算法的时间复杂度 若n为主串长度,m为子串长度则 最好的情况是:一配就中,只比较了m次。 最坏的情况是:主串前面n-m个位置都部分匹配到子串的最后一位,即这n-m位比较了m次,最后m位也各比较了一次,还要加上m,所以总次数为:(n-m)*m+m=(n-m+1)*m从最好到最坏情况统计总的比较次数,然后取平均,得到一般情况是o(n+m).

字符串匹配算法总结

Brute Force(BF或蛮力搜索) 算法: 这是世界上最简单的算法了。 首先将匹配串和模式串左对齐,然后从左向右一个一个进行比较,如果不成功则模式串向右移动一个单位。 速度最慢。 那么,怎么改进呢? 我们注意到Brute Force 算法是每次移动一个单位,一个一个单位移动显然太慢,是不是可以找到一些办法,让每次能够让模式串多移动一些位置呢? 当然是可以的。 我们也注意到,Brute Force 是很不intelligent 的,每次匹配不成功的时候,前面匹配成功的信息都被当作废物丢弃了,当然,就如现在的变废为宝一样,我们也同样可以将前面匹配成功的信息利用起来,极大地减少计算机的处理时间,节省成本。^_^ 注意,蛮力搜索算法虽然速度慢,但其很通用,文章最后会有一些更多的关于蛮力搜索的信息。 KMP算法 首先介绍的就是KMP 算法。 这个算法实在是太有名了,大学上的算法课程除了最笨的Brute Force 算法,然后就介绍了KMP 算法。也难怪,呵呵。谁让Knuth D.E. 这么world famous 呢,不仅拿了图灵奖,而且还写出了计算机界的Bible (业内人士一般简称TAOCP). 稍稍提一下,有个叫H.A.Simon的家伙,不仅拿了Turing Award ,顺手拿了个Nobel Economics Award ,做了AI 的爸爸,还是Chicago Univ的Politics PhD ,可谓全才。 KMP 的思想是这样的: 利用不匹配字符的前面那一段字符的最长前后缀来尽可能地跳过最大的距离 比如 模式串ababac这个时候我们发现在c 处不匹配,然后我们看c 前面那串字符串的最大相等前后缀,然后再来移动 下面的两个都是模式串,没有写出来匹配串 原始位置ababa c 移动之后aba bac 因为后缀是已经匹配了的,而前缀和后缀是相等的,所以直接把前缀移动到原来后缀处,再从原来的c 处,也就是现在的第二个b 处进行比较。这就是KMP 。 Horspool算法。 当然,有市场就有竞争,字符串匹配这么大一个市场,不可能让BF 和KMP 全部占了,于是又出现了几个强劲的对手。

实验三____串的模式匹配

实验三串的模式匹配 一、实验目的 1.利用顺序结构存储串,并实现串的匹配算法。 2.掌握简单模式匹配思想,熟悉KMP算法。 二、实验要求 1.认真理解简单模式匹配思想,高效实现简单模式匹配; 2.结合参考程序调试KMP算法,努力算法思想; 3.保存程序的运行结果,并结合程序进行分析。 三、实验内容 1、通过键盘初始化目标串和模式串,通过简单模式匹配算法实现串的模式匹配,匹配成功后要求输出模式串在目标串中的位置; 2、参考程序给出了两种不同形式的next数组的计算方法,请完善程序从键盘初始化一目标串并设计匹配算法完整调试KMP算法,并与简单模式匹配算法进行比较。 参考程序: #include "stdio.h" void GetNext1(char *t,int next[])/*求模式t的next值并寸入next数组中*/ { int i=1,j=0; next[1]=0; while(i<=9)//t[0] { if(j==0||t[i]==t[j]) {++i; ++j; next[i]=j; } else j=next[j]; } } void GetNext2(char *t , int next[])/* 求模式t 的next值并放入数组next中 */ { int i=1, j = 0; next[1]= 0; /* 初始化 */ while (i<=9) /* 计算next[i+1] t[0]*/ { while (j>=1 && t[i] != t[j] ) j = next[j]; i++; j++;

if(t[i]==t[j]) next[i] = next[j]; else next[i] = j; } } void main() { char *p="abcaababc"; int i,str[10]; GetNext1(p,str); printf("\n"); for(i=1;i<10;i++) printf("%d",str[i]); GetNext2(p,str); printf("\n"); for(i=1;i<10;i++) printf("%d",str[i]); printf("\n\n"); }

MySQL中的字符串模式匹配.

MySQL中的字符串模式匹配 本文关键字:MySQL 字符串模式匹配 MySQL提供标准的SQL模式匹配,以及一种基于象Unix实用程序如vi、grep 和sed的扩展正则表达式模式匹配的格式。 标准的SQL模式匹配 SQL的模式匹配允许你使用“_”匹配任何单个字符,而“%”匹配任意数目字符(包括零个字符)。在 MySQL中,SQL的模式缺省是忽略大小写的。下面显示一些例子。注意在你使用SQL模式时,你不能使用=或!=;而使用LIKE或NOT LIKE比较操作符。 例如,在表pet中,为了找出以“b”开头的名字: +--------+--------+---------+------+------------+------------+ | name | owner | species | sex | birth | death | +--------+--------+---------+------+------------+------------+ | Buffy | Harold | dog | f | 1989-05-13 | NULL | | Bowser | Diane | dog | m | 1989-08-31 | 1995-07-29 | +--------+--------+---------+------+------------+------------+ 为了找出以“fy”结尾的名字:

+--------+--------+---------+------+------------+-------+ | name | owner | species | sex | birth | death | +--------+--------+---------+------+------------+-------+ | Fluffy | Harold | cat | f | 1993-02-04 | NULL | | Buffy | Harold | dog | f | 1989-05-13 | NULL | +--------+--------+---------+------+------------+-------+ 为了找出包含一个“w”的名字: +----------+-------+---------+------+------------+------------+ | name | owner | species | sex | birth | death | +----------+-------+---------+------+------------+------------+

KMP字符串模式匹配算法解释

个人觉得这篇文章是网上的介绍有关KMP算法更让人容易理解的文章了,确实说得很“详细”,耐心地把它看完肯定会有所收获的~~,另外有关模式函数值next[i]确实有很多版本啊,在另外一些面向对象的算法描述书中也有失效函数f(j)的说法,其实是一个意思,即next[j]=f(j-1)+1,不过还是next[j]这种表示法好理解啊: KMP字符串模式匹配详解 KMP字符串模式匹配通俗点说就是一种在一个字符串中定位另一个串的高效算法。简单匹配算法的时间复杂度为O(m*n);KMP匹配算法。可以证明它的时间复杂度为O(m+n).。 一.简单匹配算法 先来看一个简单匹配算法的函数: int Index_BF ( char S [ ], char T [ ], int pos ) { /* 若串S 中从第pos(S 的下标0≤pos

串的朴素模式匹配算法(BF算法)

//算法功能:串的朴素模式匹配是最简单的一种模式匹配算法,又称为 Brute Force 算法,简称为BF算法 #include #include #define MAXL 255 #define FALSE 0 #define TRUE 1 typedef int Status; typedef unsigned char SString[MAXL+1]; //生成一个其值等于串常量strs的串T void StrAssign(SString &T, char *strs) { int i; T[0] = 0; //0号单元存储字串长度 for(i = 0; strs[i]; i++) //用数组strs给串T赋值 T[i+1] = strs[i]; T[0] = i; } //返回子串T在主串S中第pos个字符开始匹配的位置,若不存在,则返回0 int Index(SString S, SString T, int pos) { int i = pos, j = 1; while(i <= S[0] && j <= T[0]) { if(S[i] == T[j]) //继续比较后面的字符 { i++; j++; } else//指针回退,重新开始匹配 { i = i -j + 2; j = 1; } } if(j > T[0]) return i - T[0]; else return 0;

int main() { SString S, T; int m; char strs1[MAXL]; //建立主串S char strs2[MAXL]; //建立模式串T printf("请输入主串和子串:\n"); printf("主串S: "); scanf("%s", strs1); printf("子串T: "); scanf("%s", strs2); StrAssign(S, strs1); StrAssign(T, strs2); m = Index(S, T, 1); if(m) printf("主串 S = {%s}\n子串 T = {%s}\n在第 %d 个位置开始匹配!\n", strs1, strs2, m); else printf("主串 S = {%s}\n子串 T = {%s}\n匹配不成功!\n", strs1, strs2); return 0; }

模式匹配KMP算法实验步骤

一、问题描述 模式匹配两个串。 二、设计思想 这种由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现的改进的模式匹配算法简称为KM P算法。 注意到这是一个改进的算法,所以有必要把原来的模式匹配算法拿出来,其实理解的关键就在这里,一般的匹配算法: int Index(String S,String T,int pos)//参考《数据结构》中的程序 { i=pos;j=1;//这里的串的第1个元素下标是1 while(i<=S.Length && j<=T.Length) { if(S[i]==T[j]){++i;++j;} else{i=i-j+2;j=1;}//**************(1) } if(j>T.Length) return i-T.Length;//匹配成功 else return 0; } 匹配的过程非常清晰,关键是当‘失配’的时候程序是如何处理的?为什么要回溯,看下面的例子: S:aaaaabababcaaa T:ababc aaaaabababcaaa ababc.(.表示前一个已经失配) 回溯的结果就是 aaaaabababcaaa a.(babc) 如果不回溯就是 aaaaabababcaaa aba.bc 这样就漏了一个可能匹配成功的情况 aaaaabababcaaa ababc 这是由T串本身的性质决定的,是因为T串本身有前后'部分匹配'的性质。如果T为a bcdef这样的,大没有回溯的必要。

改进的地方也就是这里,我们从T串本身出发,事先就找准了T自身前后部分匹配的位置,那就可以改进算法。 如果不用回溯,那T串下一个位置从哪里开始呢? 还是上面那个例子,T为ababc,如果c失配,那就可以往前移到aba最后一个a的位置,像这样: ...ababd... ababc ->ababc 这样i不用回溯,j跳到前2个位置,继续匹配的过程,这就是KMP算法所在。这个当T[j]失配后,j应该往前跳的值就是j的next值,它是由T串本身固有决定的,与S串无关。 《数据结构》上给了next值的定义: 0 如果j=1 next[j]={Max{k|1aaab ->aaab ->aaab 像这样的T,前面自身部分匹配的部分不止两个,那应该往前跳到第几个呢?最近的一个,也就是说尽可能的向右滑移最短的长度。 到这里,就实现了KMP的大部分内容,然后关键的问题是如何求next值?先看如何用它来进行匹配操作。 将最前面的程序改写成: int Index_KMP(String S,String T,int pos) { i=pos;j=1;//这里的串的第1个元素下标是1 while(i<=S.Length && j<=T.Length) {

C语言字符串模式匹配

数据结构面试之十四——字符串的模式匹配 题注:《面试宝典》有相关习题,但思路相对不清晰,排版有错误,作者对此参考相关书籍和自己观点进行了重写,供大家参考。 十四、字符串的模式匹配 1. 模式匹配定义——子串的定位操作称为串的模式匹配。 2. 普通字符串匹配BF算法(Brute Force 算法,即蛮力算法) 【算法思想】: 第(1)步;从主串S的第pos个字符和模式的第一个字符进行比较之,若相等,则继续逐个比较后续字符;否则从主串的下一个字符起再重新和模式串的字符比较之。 第(2)步骤;依次类推,直至模式T中的每一个字符依次和主串S中的一个连续的字符序列相等,则称匹配成功;函数值为和模式T中第一个字符相等的字符在主串S中的序号,否则称为匹配不成功,函数值为0。 比如对于主串S=”abacababc”; 模式串T=”abab”; 匹配成功,返回4。 对于主串S=”abcabcabaac”; 模式串T=”abab”; 匹配不成功,返回0。 【算法实现】: //普通字符串匹配算法的实现 int Index(char* strS, char* strT, int pos) { //返回strT在strS中第pos个字符后出现的位置。 int i = pos; int j = 0; int k = 0; int lens = strlen(strS);

int lent = strlen(strT); while(i < lens && j < lent) { if(strS[i+k] == strT[j]) { ++j; //模式串跳步 ++k; //主串(内)跳步 } else { i = i+1; j=0; //指针回溯,下一个首位字符 k=0; } }//end i if(j >= lent) { return i; } else { return 0; } }//end [算法时间复杂度]:设主串长度为m,模式串的长度为n。一般情况下n

串的模式匹配算法

串的匹配算法——Brute Force (BF)算法 匹配模式的定义 设有主串S和子串T,子串T的定位就是要在主串S中找到一个与子串T相等的子串。通常把主串S称为目标串,把子串T称为模式串,因此定位也称作模式匹配。模式匹配成功是指在目标串S中找到一个模式串T;不成功则指目标串S中不存在模式串T。 BF算法 Brute-Force算法简称为BF算法,其基本思路是:从目标串S的第一个字符开始和模式串T中的第一个字符比较,若相等,则继续逐个比较后续的字符;否则从目标串S的第二个字符开始重新与模式串T的第一个字符进行比较。以此类推,若从模式串T的第i个字符开始,每个字符依次和目标串S中的对应字符相等,则匹配成功,该算法返回i;否则,匹配失败,算法返回0。 实现代码如下: /*返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0. /*T非空。 int index(String S, String T ,int pos) { int i=pos; //用于主串S中当前位置下标,若pos不为1则从pos位置开始匹配int j =1; //j用于子串T中当前位置下标值 while(i<=S[0]&&j<=T[0]) //若i小于S长度且j小于T的长度时循环 { if(S[i]==T[j]) //两个字母相等则继续 { ++i; ++j; } else //指针后退重新开始匹配 { i=i-j+2; //i退回到上次匹配首位的下一位 j=1; } if(j>T[0]) return i-T[0]; else return 0; } }

BF算法的时间复杂度 若n为主串长度,m为子串长度则 最好的情况是:一配就中,只比较了m次。 最坏的情况是:主串前面n-m个位置都部分匹配到子串的最后一位,即这n-m位比较了m 次,最后m位也各比较了一次,还要加上m,所以总次数为:(n-m)*m+m=(n-m+1)*m 从最好到最坏情况统计总的比较次数,然后取平均,得到一般情况是O(n+m).

字符串模式匹配

实验7、字符串查找 目的 掌握字符串模式匹配的经典算法。 问题描述 分别用简单方法和KMP方法实现index在文本串中查找指定字符串的功能。 步骤 1.定义字符串类型 2.实现简单的index操作,从文本串中查找指定字符串。 3.实现KMP方法的index操作,从文本串中查找指定字符串。 4.[选]建立一个文本文件,读入每一行来测试自己完成的练习,观察并理解程序的各 个处理。 设备和环境 PC计算机、Windows操作系统、C/C++开发环境 结论 能够理解和掌握字符串模式匹配的典型算法。 思考题 1.对KMP算法分别用手工和程序对某个模式串输出next和nextval。 朴素算法: #include #include #define NOTFOUND -1

#define ERROR -2 #define MAXLEN 100//字符串的最大长度 char S[MAXLEN+10],T[MAXLEN+10],st[MAXLEN+10];//串S和串T int S0,T0; //S0:串S的长度 T0:串T的长度 int pos; //pos的起始位置 void Init(char *S,int &S0)//读入字符串 { int len,i; New_Input: scanf("%s",st);//读入字符串 len=strlen(st); if (len>MAXLEN)//如果字符串的长度大于规定的字符串最大长度 { printf("This String is too long,Please Input a new one.nn"); goto New_Input;//重新读入字符串

串匹配问题:BF算法、KMP算法、BM算法

一、实验内容和目的 1、深刻理解并掌握蛮力算法的设计思想; 2、提高应用蛮力算法设计算法的技能; 3、理解这样一个观点:用蛮力法设计的算法,一般来说,经过适度的努 力后,都可以对算法的第一个版本进行一定程度的改良,改进其时 间性能。 二、实验原理及基本技术路线图(方框原理图) 串匹配问题——给定两个串S=“s1s2…s n” 和T=“t1t2…t m”,在主 串S中查找子串T的过程称为串匹配,也称模式匹配。 串匹配问题属于易解问题。 串匹配问题的特征: (1)算法的一次执行时间不容忽视:问题规模n 很大,常常需要在 大量信息中进行匹配; (2)算法改进所取得的积累效益不容忽视:串匹配操作经常被调用,执行频率高。 BF算法: 基本思想:从主串S的第一个字符开始和模式T的第一个字符进行比 较,若相等,则继续比较两者的后续字符;若不相等,则从主串S 的第二个字符开始和模式T的第一个字符进行比较,重复上述过程,若T中的字符全部比较完毕,则说明本趟匹配成功;若最后一轮匹配 的起始位置是n-m,则主串S中剩下的字符不足够匹配整个模式T, 匹配失败。这个算法称为朴素的模式匹配算法,简称BF算法。 KMP算法: 1. 在串S和串T中分别设比较的起始下标i和j; 2. 循环直到S中所剩字符长度小于T的长度或T中所有字符均比较 完毕 2.1 如果S[i]=T[j],则继续比较S和T的下一个字符;否则 2.2 将j向右滑动到next[j]位置,即j=next[j];

2.3 如果j=0,则将i和j分别加1,准备下一趟比较; 2.4 如果T中所有字符均比较完毕,则返回匹配的起始下标;否则返回0; BM算法: BM算法与KMP算法的主要区别是匹配操作的方向不同。虽然BM算法仅把匹配操作的字符比突顺序改为从右向左,但匹配发生失败时,模式T右移的计算方法却发生了较大的变化。 设计思想:设文本串T,模式串为P。首先将T与P进行左对齐,然后进行从右向左比较,若是某趟比较不匹配时,BM算法就采用两条启发式规则,即坏字符规则和好后缀规则,来计算模式串向右移动的距离,直到整个匹配过程的结束。

字符串匹配算法的研究_本科论文

字符串匹配算法的研究及其程序实现 计算机学院计算机科学与技术专业2007级指导教师:滕云 摘要:在字符串匹配算法之中,最古老和最著名的是由D. E. Knuth, J. h. Morris, V. R. Pratt 在1997年共同提出的KMP算法。直至今日,人们对字符串匹配问题还在进行着大量的研究,以寻求更简单,或者平均时间复杂度更优的算法;学者们在不同的研究方向上,设计出了很多有效的匹配算法。在现实生活中,串匹配技术的应用十分广泛,其主要领域包括:入侵检测,病毒检测,信息检索,信息过滤,计算生物学,金融检测等等。在许多应用系统中,串匹配所占的时间比重相当大,因此,串匹配算法的速度很大程度上影响着整个系统的性能。该论文重点分析了KMP算法的实现原理和C语言实现,并在此基础上提出了改进的KMP算法,使得该算法更方便实用。 关键词:KMP算法;时间复杂度;串匹配;改进;方便使用; String matching algorithm and Implementation of the Program College of Computer Sciences, Computer Science and Technology Professional grade 2007, Instructor YunTeng Abstractor:Among the string matching algorithm,the oldest and most famous is KMP algorithm co-sponsored by D.E Knuth, J. h. Morris, VR Pratt in 1997. As of today, a lot of research to String matching are still in progress, to seek a more simply or better average time complexity of the algorithm. In different research direction, scholars have designed a lot of valid matching.In real life, the string matching technique is widely used,The main areas include: intrusion detection, virus detection, information retrieval, information filtering, computational biology, financial inspection and so on.In many applications,a large percentage of the time was placed by the string matching, so the string matching algorithms significantly affect the speed performance of the whole system.The paper analyzes the implementation of the KMP algorithm theory and through the C language to achieve it.And we puts forward a modified KMP algorithm in order to makes the algorithm more convenient and practical. Key words:KMP algorithm; Time complexity; String matching; Improved; Easy to use;

字符串的模式匹配实验报告

实验题目:字符串的模式匹配 一、实验描述 用BF算法实现字符串的模式匹配 二、实验目的和任务 从主串的第pos位置字符开始和模式子串字符比较,如果相等,则继续逐个比较后续字符;否则从主串的下一个字符起再重新和模式子串的字符比较。直到找到匹配字符串或者是主串结尾。 三、概要设计 BF(Brute Force)算法是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串P的第一个字符进行匹配,若相等,则继续比较S的第二个字符和P的第二个字符;若不相等,则比较S的第二个字符和P的第一个字符,依次比较下去,直到得出最后的匹配结果。 四、运行与测试 #include #include int BFMatch(char *s,char *p) { int i,j; i =0; while(i < strlen(s)) { j = 0; while(s[i] == p[j] &&j

{ char *szSource = "ababcababa"; char *szSub = "ababa"; int index =BFMatch(szSource, szSub); printf("目标串包含匹配串的起始位置:%d",index); } 五、运行结果 六、实验心得 通过这次课程设计,让我了解了字符串的定位操作即字符串模式匹配的基本概念和算法,探讨了字符串模式匹配操作的最基本的BF匹配算法。虽然看起来很简单的程序,做起来却遇到了不少问题,编程中出行了一些小错误,多次查改之后再进行修改,所以我觉得在以后的学习中,我会更加注重实践,注重多练,多积累。

字符串匹配算法报告

课程设计报告题目:字符串匹配算法实测分析 课程名称:数据结构 专业班级:计科XX 学号:UXXXXX XX 姓名:FSH 指导教师:xxx 报告日期:2015.9.13

计算机科学与技术学院 数据结构课程组 2015年5月 题目字符串匹配算法实测分析 ?设计目的:掌握线性结构中的字符串的物理存储结构与基本算法,通过查询阅读文献资料,拓广知识面以及培养学生科研能力。 ?设计内容:结合教材上的字符串匹配算法,查询文献资料检索4种以上的有关精确匹配算法,掌握算法原理并实现。 ?设计要求: (1)查阅相关的文献资料,特别是留意年近些年发表的文献资料; (2)要求对各种算法进行理论分析,同时也对实测结果进行统计分析。测试数据要求有一定规模,比如一本书或不少于50篇的中英文文献。 (3)要求界面整洁、美观,操作方便; 报告内容: (一), 运行界面,及运行结果截图 (二),各算法的具体分析,包括起源,基本思路,实例分析,具体实现,和本算法代码。 (三),总程序源代码。 (四),课程设计心得

(一), 运行界面,运行结果说明: 运行代码显示界面: 对于S串可以手动输入字符串检索,也可以选择在计算机里建好的TXT文件,按任意键退出。 按2确认,键入一本书的TXT文件,运行如下 输入待搜索子串“史记”得到运行结果,各算法均返回子串在母串出现的位置

执行算法得运行结果,返回子串在母串所有出现位置。 结果显示运行时间用以统计时间效率: 另一段检索结果的时间截图结果显示如下: (二),各算法的具体分析 一.穷举算法(Brute force)算法: . 1.算法起源: 此算法思路简单,容易想到,没有确定的提出者‘

《KMP 字符串模式匹配算法》教学课例

《KMP字符串模式匹配算法》教学课例 程玉胜 安庆师范学院计算机与信息学院 KMP字符串模式匹配是数据结构课程中一个重要的知识点,也是一个难点(学过KMP 算法的同学100%认为:KMP是数据结构课程中最难的部分)。为了消除他们对KMP算法学习的恐惧心理,激发他们的学习兴趣,调动其积极性,显得尤为重要。 基于以上,我们根据学生的认知特点和接受水平,对教材内容进行了重新构建,并按照数据结构中?时间复杂度?概念,增加了不同模式匹配算法的运行时间,动态逼真的显示了算法的?时间?性能,获得了较好的教学效果。 一、教学目标 知识目标:让学生了解KMP算法应用的普遍性。如:在目前众多的文字处理软件中得到广泛应用,如Microsoft Word中的?查找?或?替换?操作。而这种操作实现的机制,同学们特别是计算机专业的学生很少去想过。 能力目标:要求学生体验一个完整的抽象数据类型(ADT)的实现方法和过程,并学会判断、计算算法优劣的方法。 价值目标:消除恐怖的学习心态,让学生感悟数据结构算法实际应用价值,从而激发学习的兴趣,形成积极主动式学习的态度。 二、教材分析 使用教材是清华大学严蔚敏教授并由清华大学出版社出版的《数据结构(C语言版)》,该教材难度较大,其实验方法特别是ADT方法在教材中介绍较少,而且KMP算法更是从理论分析的角度介绍了匹配算法和next的计算,自学难度很大;虽然该节知识点属于?**(表示难度较大,可以不讲)?,但是其又是考研的一个热点,所以我们又不得不讲。 三、教学重点、难点 教学重点:KMP算法中的next和改进的nextval计算 教学难点:KMP算法中如何计算next值 四、教具准备 卡片:多个字符串,字符串指针 强力磁吸:6个 五、互动式教学过程

串的模式匹配问题实验总结(用C实现)

串的模式匹配问题实验总结 1实验题目: 实现(,,) Index S T pos函数。其中,(,,) Index S T pos为串T在串S的第pos个字符后第一次出现的位置。 2实验目的: 熟练掌握串模式匹配算法。 3实验方法: 分别用朴素模式匹配和KMP快速模式匹配来实现串的模式匹配问题。具体方法如下: 朴素模式匹配:输入两个字符串,主串S和子串T,从S串的第pos个位置开始与T的第一个位置比较,若不同执行i=i-j+2;j=1两个语句;若相同,则执行语句++i; ++j;一直比较完毕为止,若S中有与T相同的部分则返回主串(S字符串)和子串(T字符串)相匹配时第一次出现的位置,若没有就返回0。 KMP快速模式匹配:构造函数get_next(char *T,int *next),求出主串S串中各个字符的next值,然后在Index_KMP(char *S,char *T,int pos)函数中调用get_next(char *T,int *next)函数并调用next值,从S串的第pos 位置开始与T 的第一个位置进行比较,若两者相等或j位置的字符next值等于0,则进行语句++i;++j;即一直向下进行。否则,执行语句j=A[j];直到比较完毕为止。 若S中有与T相同的部分则返回主串(S字符串)和子串(T字符串)相匹配时第一次出现的位置,若没有就返回0 4实验过程与结果: (1)、选择1功能“输入主串、子串和匹配起始位置”,输入主串S:asdfghjkl, 输入子串T:gh,输入pos的值为:2。 选择2功能“朴素的模式匹配算法”,输出结果为 5; 选择3功能“KMP快速模式匹配算法”,输出结果为 5; 选择0功能,退出程序。 截图如下:

数据结构 串与模式匹配

常熟理工学院 《数据结构与算法》实验指导与报告书 _2017-2018_____学年第__1__ 学期 专业:物联网工程 实验名称:串与模式匹配 实验地点: N6-210 指导教师:聂盼红 计算机科学与工程学院 2017

实验四串与模式匹配 【实验目的】 1、掌握串的存储表示及基本操作; 2、掌握串的两种模式匹配算法:BF和KMP。 3、了解串的应用。 【实验学时】 2学时 【实验预习】 回答以下问题: 1、串和子串的定义 串:串是由零个或多个任意字符组成的有限序列。 子串:串中任意连续字符组成的子序称为该串的字串。 2、串的模式匹配 串的模式匹配是数据结构中字符串的一种基本运算,给定一个子串,要求在某个字符串中找出与该子串相同的所有子串,这就是模式匹配。假设P是给定的子串,T是待查找的字符串,要求从T中找出与P相同的所有子串,这个问题成为模式匹配问题。P称为模式,T 称为目标。如果T中存在一个或多个模式为P的子串,就给出该子串在T中的位置,称为匹配成功;否则匹配失败 【实1 验内容和要求】/ 1、按照要求完成程序exp4_1.c,实现串的相关操作。调试并运行如下测试数据给出运行结果: ?求“This is a boy”的串长; ?比较”abc ?3”和“abcde“; 表示空格

?比较”english”和“student“; ?比较”abc”和“abc“; ?截取串”white”,起始2,长度2; ?截取串”white”,起始1,长度7; ?截取串”white”,起始6,长度2; ?连接串”asddffgh”和”12344”;

实验代码: #include #include #define MAXSIZE 100 #define ERROR 0 #define OK 1 /*串的定长顺序存储表示*/ typedef struct { char data[MAXSIZE]; int length; } SqString; int strInit(SqString *s); /*初始化串*/ int strCreate(SqString *s); /*生成一个串*/ int strLength(SqString *s); /*求串的长度*/ int strCompare(SqString *s1,SqString *s2); /*两个串的比较*/ int subString(SqString *sub,SqString *s,int pos,int len); /*求子串*/ int strConcat(SqString *t,SqString *s1,SqString *s2); /*两个串的连接*/ /*初始化串*/ int strInit(SqString *s) { s->length=0; s->data[0]='\0'; return OK; }/*strInit*/ /*生成一个串*/ int strCreate(SqString *s) { printf("input string :"); gets(s->data); s->length=strlen(s->data); return OK; }/*strCreate*/

数据结构- 串的模式匹配算法:BF和 KMP算法

数据结构- 串的模式匹配算法:BF和KMP算法 Brute-Force算法的思想 Brute-Force算法的基本思想是: 1) 从目标串s 的第一个字符起和模式串t的第一个字符进行比较,若相等,则继续逐个比较后续字符,否则从串s 的第二个字符起再重新和串t进行比较。 2) 依此类推,直至串t 中的每个字符依次和串s的一个连续的字符序列相等,则称模式匹配成功,此时串t的第一个字符在串s 中的位置就是t 在s中的位置,否则模式匹配不成功。 Brute-Force算法的实现

c语言实现: 1.// Test.cpp : Defines the entry point for the console application. 2.// 3.#include "stdafx.h" 4.#include 5.#include "stdlib.h" 6.#include https://www.sodocs.net/doc/5c342082.html,ing namespace std; 8. 9.//宏定义 10.#define TRUE 1 11.#define FALSE 0 12.#define OK 1 13.#define ERROR 0 14. 15.#define MAXSTRLEN 100 16. 17.typedef char SString[MAXSTRLEN + 1]; 18./************************************************************************/ 19./* 20.返回子串T在主串S中第pos位置之后的位置,若不存在,返回0 21.*/ 22./************************************************************************/ 23.int BFindex(SString S, SString T, int pos) 24.{ 25.if (pos <1 || pos > S[0] ) exit(ERROR); 26.int i = pos, j =1; 27.while (i<= S[0] && j <= T[0]) 28. { 29.if (S[i] == T[j]) 30. { 31. ++i; ++j; 32. } else { 33. i = i- j+ 2; 34. j = 1; 35. } 36. } 37.if(j > T[0]) return i - T[0]; 38.return ERROR; 39.} 40. 41. 42.

相关主题