字串—KMP演算法
阿新 • • 發佈:2020-12-11
一、KMP介紹:
KMP演算法由Knuth、Morris和Pratt 提出的字串匹配的演算法;
MKP演算法的核心則是字首表的構建,關於字首表如何去計算?很多資料在構建字首表的描述中很是簡略,對於初學者很難搞懂字首表到底是怎麼計算出來的。
為什麼在KMP字串匹配演算法中要使用字首表?
字首表的作用就是記錄當前元素及之前元素構成的子串中的最長相同前後綴的長度。
字串匹配暴力解法中需要將匹配串(長度為m)與主串(長度為n)進行每一個元素的比較。比如匹配串第一個元素和主串第一個元素比較,如果一樣,同時後移一位進行比較;如果不一樣,將主串開始匹配位置後移一位,即將匹配串第一個元素與主串的第二個元素進行比較…以此類推。這種暴力解法的時間複雜度為O(m*n)。
在說字首表的構建之前,先說明一下字首和字尾的定義。
字首:去除字串中最後一個元素的其餘連續子串;
字尾:去除字串中第一個元素的其餘連續子串;
這時得到的字首表就是原始的字首表。
KMP特殊情況:
當第i個元素不匹配時,這個元素對應的字首表值為i,所以會陷入死迴圈。
解決辦法:
1、在構建字首表時將字首表值統一-1,使用時都恢復+1。(變值)
2、或者在使用的時候將索引序號前移-1,使用時使用前移的索引號。(變索引)
二、C++程式碼
/* 字串匹配演算法:kmp演算法
*/
#include <iostream>
#include<string>
using namespace std;
void getNext(int* next,string &s){
int j = -1;
next[0] = j;
for(int i = 1;i < s.size();i++){
while(j >= 0 && s[i] != s[j+1]){
j = next[j];
}
if(s[i] == s[j+1]){
j++ ;
}
next[i] = j;
}
}
bool kmp(string &mainString,string &sonString){
if(sonString.size() == 0){
cout << "搜尋字串為空";
return false;
}
int next[sonString.size()];
int j = -1;
getNext(next,sonString);
for(int i = 0;i < mainString.size();i++){
while(j >= 0 && sonString[j+1] != mainString[i]){
j = next[j];
}
if(sonString[j+1] == mainString[i]){
j++;
}
if(j == sonString.size()-1){
cout << "字串匹配找到";
return true;
}
}
cout << "字串匹配未找到";
return false;
}
int main(){
string txt = "abaab aaababaab aabbabb";
string str = "aababa";
kmp(txt,str);
/*
int next[str.size()];
getNext(next,str);
for(int i = 0;i < str.size();i++){
cout << next[i] << "、";
}
cout << endl;
*/
return 0;
}
三、執行結果
1、示例一
2、示例二
描述錯誤地方,請指正。