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

时间:2023-01-06 23:54:42
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;
}