1. 程式人生 > 其它 >對於KMP演算法的理解

對於KMP演算法的理解

技術標籤:資料結構的學習(C++)

KMP演算法是三位偉大的計算機先驅:D.E.Knuth、J,H,Morris 和 V.R.Pratt提出的,取其姓名首字母得名KMP,KMP演算法是為了優化暴力匹配而誕生的。暴力匹配時,較長的文字串指標會多次回溯使得程式效能下降,而KMP的核心思想就是減少匹配時主串(較長的文字串)指標的回溯次數以提升程式效能。

KMP的具體概念就不寫了,直接看這位博主的吧:

KMP演算法—終於全部弄懂了

如果實在不懂KMP的話建議看下某一年《王道考研·資料結構》鹹魚學長的講課視訊,十分易懂,比強行啃書本效率高得多。我按照《王道考研·機試指南》和《王道考研·資料結構》的視訊綜合寫出瞭如下的程式碼,以供自己以後翻閱和備考複試。註釋十分詳盡,如下所示:

#include<iostream>
#include<string>
using namespace std;

//定義next陣列相關
const int MAXN = 10000;
int nextTable[MAXN];

void generateNextTable(string pattern)
{
	int m = pattern.size();//取得模式串長度
	int j = 0;//用於遍歷模式串
	nextTable[j] = -1;//設定萬用字元

	//next[j]陣列的含義是:
	//當前模式串的下標遍歷到j
	//此時匹配失敗時,需要回溯到的下標位置
	//該下標位置存放在陣列next[j]裡
	//i用於計算nextTable的具體內容
	int i = nextTable[j];

	while (j < m)
	{

		if (i == -1 || pattern[j] == pattern[i])//成功匹配
		{
			i++; j++;
			nextTable[j] = i;
			
			/*
			//按照虛擬碼next[j+1]=next[j]+1來寫的話,因該是:
			nextTable[j+1]=nextTable[j]+1;
			i++;j++;
			//上文nextTab[j]=i,只是因為先進行了i和j的自增
			//本質時一樣的
			*/		
		}
		else//匹配失敗
		{
			i = nextTable[i];
		}
	}
	return;
}

int KMP(string text, string pattern)
{
	//先生成輔助陣列next,才可以進行KMP演算法
	generateNextTable(pattern);
	//取得文字串長度
	int n = text.size(); 
	//取得模式串長度
	int m = pattern.size();
	//i用於遍歷文字串text,j用於遍歷模式串pattern
	int i = 0; int j = 0;
	while (i < n&&j < m)
	{
		if (j == -1 || text[i] == pattern[j])//匹配成功
		{
			i++; j++;
		}
		else//匹配失敗
		{
			j = nextTable[j];//根據已有的next陣列回溯
		}
	}
	if (m == j)return i - j;//成功匹配完成全部的模式串,返回首次出現位置
	else return -1;//沒能匹配完成全部的模式串

}


int main(void)
{
	string pattern, text;
	getline(cin, text);
	getline(cin, pattern);
	cout << KMP(text, pattern) << endl;
	system("pause");
	return 0;

這是輸出示例: