一、问题描述
实现KMP算法
二、实现思路
在KMP算法中,首先分析模式串t从中提取出加速匹配的有用信息next数组,紧接着利用计算好的模式串的next数组进行模式匹配。其中,next数组有效地消除了主串指针的回溯,提高算法效率
- 第一部分,对模式串预处理,生成next数组。next数组的求解过程如下:
(1)置next[0]=-1,next[1]=0。
(2)如果next[j]=k,表示有”t0t0…tk-1”=”tj-k-tj-k+1…tj-I”:
①若tk=tj,既有”t0t0…tk-1tk”=”tj-k-tj-k+1…tj-I tj”,显然有next[j+1]=k+1。
②若tk≠tj,说明tj之前不存在长度为next[j]+1的子串和开头字符起的子串相同,设k’=next[k],则下一步应该将tj与tk’比较:若tj=tk’,则说明tj之前存在长度为next[k’]+1的子串和开头字符起的子串相同;否则依次类推找更短的子串,直到不存在可匹配的子串,置next[j+1]=0。所以,当tk≠tj时,置k=next[k]。
- 第二部分,利用计算好的模式串的next数组进行模式匹配。过程如下:
假设指针i和j分别指向目标串s和模式串t。首先将i和j分别置0,再分别扫描目标串s和模式串t,如果j=-1或者i和j指向的字符相同,i和j分别自增1;否则,i不变,j回退到j=next[j]即模式串右滑.当跳出循环后,通过j的值进行判断。如果j超界,说明模式匹配成功,返回i-t的长度;否则,说明模式匹配失败,返回值-1.
三、程序代码
#include<iostream>
using namespace std;
#define MaxSize 50
typedef struct //类型声明
{
char data[MaxSize];
int length;
}SqString;
void StrAssign(SqString & s, char cstr[]) //将字符串常量cstr赋给串
{
int i;
for (i = 0; cstr[i] != '\0'; i++)
s.data[i] = cstr[i];
s.length = i;
}
void DestroyStr(SqString &s) {} //销毁串
void GetNext(SqString t, int next[]) //由模式串t求出next数组
{
int j, k;
j = 0; k = -1;
next[0] = -1;
while (j < t.length - 1)
{
if (k == -1 || t.data[j] == t.data[k])
{
next[j++] = k++;
}
else
k = next[k];
}
}
int KMPIndex(SqString s, SqString t) //KMP算法
{
int next[MaxSize], i = 0, j = 0;
GetNext(t, next);
while (i < s.length&&j < t.length)
{
if (j == -1 || s.data[i] == t.data[j])
{
i++; j++;
}
else j = next[j];
}
if (j >= t.length)
return(i - t.length);
else
return -1;
}
int main()
{
char a[MaxSize], b[MaxSize];
SqString astr, bstr;
cout << "请输入目标串:";
cin >> a;
cout << "请输入模式串:";
cin >> b;
StrAssign(astr, a);
StrAssign(bstr, b);
cout <<"模式串位置为:"<< KMPIndex(astr, bstr) << endl;
}