字符串匹配的KMP算法
举例来说,有一个字符串”BBC ABCDAB ABCDABCDABDE”,我想知道,里面是否包含另一个字符串”ABCDABD”?
1、字符串”BBC ABCDAB ABCDABCDABDE”的第一个字符与搜索词”ABCDABD”的第一个字符,进行比较。因为B与A不匹配,所以搜索词后移一位。
2、因为B与A不匹配,搜索词再往后移。
3、就这样,直到字符串有一个字符,与搜索词的第一个字符相同为止。
4、接着比较字符串和搜索词的下一个字符,还是相同。
5、直到字符串有一个字符,与搜索词对应的字符不相同为止。
6、这时,最自然的反应是,将搜索词整个后移一位,再从头逐个比较。这样做虽然可行,但是效率很差,因为你要把”搜索位置”移到已经比较过的位置,重比一遍。
7、一个基本事实是,当空格与D不匹配时,你其实知道前面六个字符是”ABCDAB”。KMP算法的想法是,设法利用这个已知信息,不要把”搜索位置”移回已经比较过的位置,继续把它向后移,这样就提高了效率。
8、借助最长公共前缀后缀长度数组,将模式串向左移动合适的位置。
#include <iostream> #include <string.h> #include <stdio.h> using namespace std ; int next[100] ; void getNext( char p[] ) { int len = strlen(p) ; next[0] = 0 ; int i = 0 , j = 0 ; for(j = 1 ; j < len ; j++) { // i 代表最长前缀后缀长度 while( p[i] != p[j] && i > 0 ) // 当p[i] != p[j] 时,减小最长前缀后缀长度 i = next[i-1] ; if(p[i] == p[j]) { i++ ; //最长公共前缀后缀长度+1 next[j] = i ; //匹配失败时跳到该处 } else next[j] = 0 ; } } int main() { char p[100] ; cin >> p ; int lenp = strlen(p) ; getNext(p); char s[1000] ; getchar() ; gets(s) ; int lens = strlen(s) ; int j = 0 ; bool flag = false ; for(int i = 0 ; i < lens ; i++) { if(p[j] == s[i]) j++ ; else if(j-1 >= 0) j = next[j-1] ; if(j == lenp) { flag = true ; j = i ; break ; } } cout <<"结束位置:"<< j+1 << endl ; if(flag) cout << "YES" << endl ; else cout << "NO" << endl ; return 0 ; }