KMP字符串匹配算法的原理与实现

时间:2023-01-06 23:54:18
KMP字符串匹配算法的原理与实现

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth与V.R.Pratt和J.H.Morris同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。

KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。即确定下一次应该从那个位置重新开始匹配。

char*obj = "cbcba";

char*src = "sdcbcbcba";

要在src中寻找obj,过程如下:

从src第0位开始匹配,s匹配失败,移动1位,

从d开始匹配,d匹配失败,移动1位,

接着从src第2位c开始,匹配,继续b,匹配,继续c,匹配,继续b,匹配,继续c,不匹配,

KMP算法关键点就在这里,要移动最大的距离,在这里是2位,即从src第二位移动到第四位,下次从第四位的c开始匹配。

对于一个要查找的目标字符串,每次在哪一位匹配失败后要移动的最大距离可以提前算出来,存到一个数组里,匹配时直接查找就行。


纯粹自己实现,代码有些丑陋,呵呵


// KMP.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<iostream>
using namespace std;

int*kk;
int*kkk;

int KMP(char*src, char*obj)
{
int k1 = 0;
int k2 = 0;
int len1 = strlen(src);
int len2 = strlen(obj);
while (k1 < len1)
{
if (src[k1] != obj[0])
{
++k1;
continue;
}
while (k2 < len2+1&&k1+k2 < len1+1)
{
if (k2 == len2)
return k1;
if (src[k1 + k2] == obj[k2])
++k2;
else
if (kkk[k2] == 1)
{
k1 = k1 + kk[k2];
k2 = 0;
continue;
}
else
if (obj[k2 - kk[k2]] == src[k1 + k2])
{
k1 = k1 + kk[k2];
k2 = 0;
continue;
}
else
{
k1 = k1 + k2 + 1;
k2 = 0;
continue;
}

}
}

return -1;

}


int* shift(char*obj)
{
int len = strlen(obj);
kk = new int[len];
kkk = new int[len];
for (int i = 0; i < len; i++)
{
kkk[i ]= 0;
}
kk[0] = 1;
if (len > 1)
{
if (obj[0] == obj[1])
{
kk[1] = 2;
kkk[1] = 1;
}
else
kk[1] = 1;//条件是src与obj第1位匹配的字符等于obj第0个字符,否则kk[1]=2,这由匹配时的src决定
}


int k = 2;
int n = 0;
int m = 1;
while (k < len)
{
bool flag = false;
bool flag1 = false;
while (m<k)
{

if (obj[m] != obj[n])
{
++m;
continue;
}
while (obj[m] == obj[n])
{
flag1 = true;
if (m == k - 1)
{
flag = true;
break;
}
++m;
++n;
}
if (flag)
break;
}
if (!flag1)
if (obj[k] == obj[0])
{
kk[k] = k + 1;//此时直接后移,src无需判断
kkk[k] = 1;
n = 0;
m = 1;
++k;
continue;
}
if (obj[k] == obj[n + 1])
{
kk[k] = k + 1;//此时直接后移,src无需判断
kkk[k] = 1;
n = 0;
m = 1;
++k;
continue;
}
if (flag)
kk[k] = k - 1 - n;//此处假设src与obj第k位匹配的字符等于obj第n+1个字符,否则kk[k]=k+1,kmp匹配时需做判断
else
kk[k] = k;//此处假设src与obj第k位匹配的字符等于obj第0个字符,否则kk[k]=k+1,kmp匹配时需做判断
n = 0;
m = 1;
++k;

}

return kk;
}




int _tmain(int argc, _TCHAR* argv[])
{
//char*obj = "cbcba";
//char*src = "sdcbcbcba";
//char*src = "abacaabacabacabaabb";
//char*obj = "abacab";
char*src = "BBC ABCDAB ABCDABCDABDE";
char*obj = "ABCDABD";
int len = strlen(obj);
shift(obj);
for (int i = 0; i < len; i++)
cout << kk[i] << endl;
cout << endl;
for (int i = 0; i < len; i++)
cout << kkk[i] << endl;
cout << KMP(src, obj) << endl;
system("pause");
return 0;
}