KMP算法

#include 
#include 
#include 
#include 
using namespace std;

const int maxn = 1000;
int mynext[maxn], nextval[maxn];
//t = next[j]表明p[0,j]的前缀和后缀相等的末尾下标是t,即p[0,t]是完全匹配的
//next[j]表示j+1位匹配失败但j往前的匹配成功应该退回去的位置,退回去后仍然保持p[0,next[j]]是前后缀匹配的
void getNext(char s[], int len){
     int j = -1;//p[0,j]是已经完全匹配的
     mynext[0] = -1;//这个是没有匹配的
     for(int i = 1; i < len; i ++){
          //如果当前比较位i不等于已经完全匹配的下一个字符 ,j继续向前移动直到等于或j == -1
          while(j != -1 && s[i] != s[j + 1]){
               j = mynext[j];//反复令j回退,每一步回退都会保证p[0,j]是完全匹配的。因为[0,j]是匹配的,也就是原串是这样的,要想缩短后继续匹配,其实是找[0,j]的最长相等前后缀。即next[j];
          }
          //上面的迭代有两种可能,
          //一种是j=-1,代表没有匹配的,那这步比较是为了判断首字母相不相同
          //还有就是找到一个位置 使得s[i] == s[j + 1],那么理应向后移动一个
          if(s[i] == s[j + 1]){
               j ++;
          }
          mynext[i] = j;
     }
}

void getNextval(char s[], int len){
     int j = -1;//表示模式串中已经匹配的下标
     nextval[0] = -1;
     //第i位是不匹配的
     for(int i = 1; i < len; i ++){
          while(j != -1 && s[i] != s[j + 1]){
               j = nextval[j];
          }
          if(s[i] == s[j + 1]){
               j ++;
          }
          //如果一个也没有匹配或者超过一个匹配上了,
          //这时不匹配的位置i已经匹配上了,为了避免重复,需要判断下一位相同不相同
          if(j == -1 || s[i + 1] != s[j + 1]){
               nextval[i] = j;
          }
          else nextval = nextval[j];
     }
}

bool KMP(char text[], char patten[]){
     int n = strlen(text), m = strlen(patten);
     getNext(patten, m);//得到next数组
     int j = -1;//表示p[0,j]已经与text匹配
     for(int i = 0; i < n; i ++){
          while(j != -1 && text[i] != patten[j + 1]){
               j = mynext[j];
          }
          //还是判断当前位有没有匹配上
          if(text[i] == text[j + 1]){
               j ++;
          }
          //判断完全已经匹配的是不是p[0, m-1]
          if(j == m - 1){
               return true;
          }
     }
     return false;
}

int main()
{
     char a[10], b[10];
     scanf("%s%s", a, b);
     bool res = KMP(a, b);
     if(res) printf("Yes\n");
     else printf("No\n");
     return 0;
}

你可能感兴趣的:(数据结构高分笔记)