KMP串匹配
- 对BF进行优化
- i不用回退
- j回退到,已匹配部分出现的(必须以0开头)与此时j下标之后(即,i下标之后)(必须以j-1结尾)出现的具有相同子串位置的下一位,k
0-(k-1)=x-(j-1)
x=j-k
0-(k-1)=(j-k)-(j-1)
- 即,j回退到next[j]
- 将串sub所有位置出现相同子串的最大长度,置于数组next中,定义next[0]为-1
- next[0]= -1;
- next[1] = 0;
- next[j] ,j从2开始
- 从j的前一位j-1逆推,
此时next[j-1] =k,即:0-(k-1)=(j-k)-(j-2)
如果sub[k]==sub[j-1],则:0-k=(j-k)-(j-1)
则:next[j]=k+1 - 从j的前一位j-1逆推,
此时next[j-1] =k
如果sub[k]!=sub[j-1],则重新开始计数,k变为求’0~k’子串最后一位的k值
则:k = next[k]('0~k’子串最后一位的下标为k)
此时,重新判断:sub[k] ? sub[j-1]
当持续出现不等,k= -1时,next[j]=k+1=0
//str.h头文件
#pragma once
#define SIZE 20
typedef struct Str//定义串结构体
{
char elem[SIZE];
int length;//串中没有'\0'
}Str;
1 求next数组
#include"str.h"//引入头文件
#include<stdio.h>
void Getnext(int* next, Str* sub)
{
next[0] = -1;
next[1] = 0;
int j = 2;
int k = 0;//j-1的k值
while (j < sub->length)
{
if (sub->elem[j - 1] == sub->elem[k] || k == -1)//如果前一个位置j-1的字符和k位置的字符相等,则该位置j的k值就等于前一个位置的k值加1
{ //当持续出现不等时,k变为-1,此时该位置的j=++k=0
/*next[j] = k + 1;
j++;
k++;*/
next[j++] = ++k;//此时,k更新为该位置j的k值,需要加1
}
else
{
k = next[k];//当持续出现不等时,k变为-1
}
}
}
2 KMP算法
#include"str.h"//引入头文件
#include<stdio.h>
#include <malloc.h>
#include <cassert>
int KMP(Str* s, Str* sub, int pos)
{
int i = pos;
int j = 0;
int* next = (int*)malloc(sub->length * sizeof(int));
assert(next != NULL);
Getnext(next, sub);
Getnext_fix(next, sub, sub->length);
while (i < s->length && j < sub->length)
{
if (s->elem[i] == sub->elem[j] || j == -1)//当第一位就不匹配时,j=next[0]=-1,此时也需要j++
{
i++;
j++;
}
else
{
j = next[j];//当第一位就不匹配时,j=next[0]=-1
}
}
free(next);
next = NULL;
if (j == sub->length)
{
return i - j;
}
return -1;
}
3 求next数组练习
求next数组练习:
‘a b a b c a b c d a b c d e’
-1,0,0,1,2,0,1,2,0,0,1,2,0,0
‘a b c a b c a b c a b c d a b c d e’
-1,0,0,0,1,2,3,4,5,6,7,8,9,0,1,2,3,0
‘a b a b c a b c d a b c d e’
-1,0,0,1,2,0,1,2,0,0,1,2,0,0
‘a b c d a b c a b c d a b c d a’
-1,0,0,0,0,1,2,3,1,2,3,4,5,6,7,4
next数组修正:
如果:sub[j]=sub[ next[j] ](sub[k])
则:next[j] = next[ next[j] ](k=next[k])
‘a a a a a a a a b’
-1, 0, 1, 2, 3, 4, 5, 6, 7
-1,-1,-1,-1,-1,-1,-1,-1,7(修正)
‘a b c a a b b c a b c a a b d a b’
-1, 0, 0, 0, 1, 1, 2, 0, 0, 1, 2, 3, 4, 5, 6, 0, 1
-1, 0, 0,-1, 1, 0, 2, 0,-1, 0, 0,-1, 1, 0, 6,-1, 0(修正)
4 next数组的修正
#include"str.h"//引入头文件
#include<stdio.h>
void Getnext_fix(int* next, Str* sub, int len)
{
for (int j = 1; j < len; j++)
{
if (sub->elem[j] == sub->elem[next[j]])//如果下标j的字符和其k值位置的字符相等,则下标j的k值等于其下标k的k值
{
next[j] = next[next[j]];
}
}
}