//先贴代码,简介有空再补
//代码根据 B站UP:正月点灯笼 KMP算法视频编写
B站空间:https://space.bilibili.com/24014925?from=search&seid=10696955474489806893
视频链接:
Part Ⅰ.
Part Ⅱ.
#include<bits/stdc++.h>
#include<string.h>
using namespace std;
/*
对于T子串(待匹配字串)不重复访问字符,即每次比较都是从T的失效位开始的
在pattern中,0到i位的前缀找最大相同前后缀串位数
是为了第i+1位失配时找P的匹配位x,
假设从P的x位开始匹配,
那么P的0到x-1位与T的失配位往前数x位必须是一样的,
就是P的最大相同前缀和后缀,
这就是前缀表。
*/
/*
求前缀表
pattern - 匹配字串
prefix - 前缀表
n - pattern 长度
*/
void prefix_table(char pattern[],int prefix[],int n){
prefix[0] = 0;//前缀表第一项为0
int len = 0;//最长公共前后缀的长度
int i = 1;
while( i < n){
cout<<"i = "<<i<<" len = "<<len<<endl;
if(pattern[i] == pattern[len]){
len++;
prefix[i] = len;
i++;
}
else{
if(len > 0){
len = prefix[len - 1];
}
//如果已经退到边界
else{
prefix[i] = len;//此时len = 0
i++;
}
}
}
}
void prefix_table_move(int prefix[],int n){
for(int i = n - 1 ; i > 0 ;i --){
prefix[i] = prefix[i - 1];
}
prefix[0] = -1;
}
int kmp_search(char text[],char pattern[]){
int n = strlen(pattern);
int m = strlen(text);
int *prefix = (int *)malloc(sizeof(int) * n);
prefix_table(pattern,prefix,n);
prefix_table_move(prefix,n);
/*
for(int i = 0 ; i < n;i++){
cout<<pattern[i]<<" ";
}
cout<<endl;
for(int i = 0 ; i < n;i++){
cout<<prefix[i]<<" ";
}
*/
//text[i] len(text) = m
//pattern [j] len(pattern) = n
int i = 0 , j = 0;
while(i < m && j < n){
cout<<"i = "<<i <<"j = "<<j<<endl;
//如果相等
if(text[i] == pattern[j]){
i++;
j++;
}
//如果不等
else{
j = prefix[j];
//如果第一个匹配不上,
if(j == -1){
i++,j++;
}
}
}
if(j >= n){
return i - j;
}
else{
return -1;
}
}
int main(){
char text[] = "ABABABAABAABABABAB";
char pattern[] = "ABABCABAA";
int prefix[9];
int n = 9;
int ans = kmp_search(text,pattern);
cout<<ans;
return 0;
}