/**
KMP算法
算法思想:
T0....T(j-i)......T(j-1) Tj
= = !=
p0 P(i-1) Pi
即在比較的過程中有
P(0...i-1) = T(j-i....j-1) 再往下匹配時 Pi =!Tj
如果找到K值使
P(0..i-k-1) = p(k..i-1)
這樣字符創P可以移動K位
因爲P(k..i-1)與Tj-1前面的i-1-K爲相等
所以P(0..i-k-1)也與Tj-1前面的i-1-K爲相等
因此只需要比較P(i-k) 和Tj就行了
*/
#include <iostream>
#include <string>
using namespace std;
/**
尋找模式串P每個字符的特徵數
即每個字符前P(0...i-1)的最大相同前綴子串和後綴子串
Next(i) = -1 當i = 0使
max{k:0 < k < i && P(0...k-1) = P(i-k...i-1) } K存在
0 K不存在
*/
int * findNext(string P)
{
int i = 0;
int m = P.length();
int * Next = new int[m];
Next[0] = -1;
int k = -1;
//從開始0-m-1循環,計算 i= 0...m-1的next的值
while(i < m)
{
//求最大的首位子串
while(k >= 0 && P[i] != P[k])
{
/**用到前邊所求的next的值
因爲是要每次都是從P的開始位置匹配
next[i]的值就是在第i個字符前面串的最大相同前綴和後綴子串
而P[k]是P的第k個字符,現在P[k]和P[i]不相等,我們應該從第
k的字符的最大相同前綴和後綴子串的位置開始重新匹配
而第K個字符的最大相同前綴和後綴子串的位置是next[k]
就是相當於把P串看成要匹配的串
*/
k = Next[k];
}
i ++;
k ++;
if(i == m) break;
//如果P[i] 和 P[k] 相等,優化
/**如果P[i] 和 P[k] 相等
則P[k]也不會和Tj相等
還需要向右移動
*/
if(P[i] == P[k])
{
Next[i] = Next[k];
}
else
Next[i] = k;
}
return Next;
}
int KMP(const string & T ,const string & P , int * Next)
{
int tLen = T.length();
int pLen = P.length();
int i = 0;
int j = 0;
if(tLen < pLen) return -1;
while(i < tLen && j < pLen)
{
if(j == -1 || T[i] == P[j])
{
i ++;
j ++;
//cout<<"j:"<<j<<endl;
}
else
{//如果不匹配,返回到最大前綴後綴子串處去匹配
j = Next[j];
}
}
//最後檢驗結果,若果j的值大於P的長度是說明子串的位置已經找到
if(j >= pLen)
{
return (i - pLen + 1);
}
else return -1;
}
int main()
{
//cout << "Hello world!" << endl;
string T = "abcdaabcab";
string P = "abc";
int * Next = findNext(P);
for(int i = 0 ; i < P.length() ; i ++)
{
cout<<Next[i]<<" ";
}
cout<<endl;
int j = KMP(T,P,Next);
cout<<j<<endl;
return 0;
}
KMP算法基本思想與實現
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.