首页 > 其他分享 >KMP字符串模式匹配详解

KMP字符串模式匹配详解

时间:2023-01-01 11:04:22浏览次数:51  
标签:字符 匹配 int 算法 详解 KMP 下标 模式匹配


KMP字符串模式匹配详解

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

一. 简单匹配算法

一个普通匹配算法的函数:

int Index_BF ( char S [ ], char T [ ], int pos ) {
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]才不等。

KMP字符串模式匹配详解_数组

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


KMP字符串模式匹配详解_数组

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

KMP字符串模式匹配详解_数组

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

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


KMP字符串模式匹配详解_数组

. 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’).

KMP字符串模式匹配详解_数组

也就是说,如果开始的两个字符之后的第三个字符也为’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]是否相等。。。

KMP字符串模式匹配详解_数组


刚才我又说:“(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]是否相等。。。

代码解释:

#include <iostream>
#include <cstring>
using namespace std;
void getNext(const char* pattern,int next[])
{\\模式串的Next[]数组的球阀










//
//
//

}
//下面是KMP模式匹配程序,各位可以用他验证。记得加入上面的函数
int KMP(const char *Text,const char* Pattern)
{ //const 表示函数内部不会改变这个参数的值。
if( !Text||!Pattern|| Pattern[0]=='\0' ||
return -1;//空指针或空串,返回-1。


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

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

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



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






return index;// 匹配成功


}
int main(){




}

感觉这个算法主要搞懂void getNext(const char* pattern,int next[])函数,再给一个Next[]例子pat[]=”abcdabcdeabc”;

KMP字符串模式匹配详解_数组

​下表的数字表示为每次循环后Next[]数组的值,,,,,

××××××××××××××××××××××××××××××××××××××××××

还有另外一种Next[]数组的表示方法:

例子pat[]=”abcdabcdeabc”;

KMP字符串模式匹配详解_数组

​​下表的数字表示为每次循环后Next[]数组的值,,,,,

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int fail[30];
char str[]="asdfgabcdabcdeabc";
char pat[]="abcdabcdeabc";
int kmp()
{


memset(fail,-1,sizeof(fail));
\\模式串的Next[]数组的球法



if
//
//
// cout<<endl;










}
int main()
{

}

标签:字符,匹配,int,算法,详解,KMP,下标,模式匹配
From: https://blog.51cto.com/u_15758326/5982797

相关文章