// KMP.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
//输入:src, slen主串
//输入:pstr, plen模式串
//输入:next KMP算法中的next函数值数组
//修正后的求next数组各值的函数代码
void GetNext(const char* pstr, int plen, int* next)
{
int i = 0,j = -1;
//???????????????????????忘了给next[0]赋初值导致崩溃
next[i] = -1;
while(i < plen - 1)//i< plen-1是因为,在最后一个++i=plen-1时,已经对其进行next赋值不用再到下一步了
{
//j=-1;开始情况;或者是前一步得到的i,j相等,i,j都往下迈进一步
if(j == -1 || pstr[i] == pstr[j])
{
++ i;
++ j;
//如果迈进过程中相等,直接赋予其next值
if(pstr[i] == pstr[j])
next[i] = next[j];
else//不等就赋予j值,因为j表示前面有多少已经判断的相等部分的长度
next[i] = j;
}
else//既不是开始j=-1,当前值也不相等,那么跳到上j的next值去
j = next[j];
}
}
int KMP_Search(char const* src,int slen,char const* pstr,int plen,int const* next,int pos)
{
int i = pos;
int j = -1;
while(i < slen && j < plen )
{
if(j == -1 || src[i] == pstr[j])
{
++ i;
++ j;
}else
j = next[j];
}
if(j >= plen)
return i - plen;
else
return -1;
}
//===========================================================================
void Test(char* testName, const string src, const string pstr, int expected)
{
if(testName != NULL)
printf("%s begins: \n", testName);
cout<<"src: "<< src<<endl;
cout<<"pstr: "<< pstr<<endl;
int* next = new int[pstr.size()];
GetNext(pstr.data(), pstr.size(), next);
int resultIndex = KMP_Search(src.data(), src.size(), pstr.data(), pstr.size(),next, 0);
if(expected == resultIndex)
printf("passed.\n");
else if(expected != resultIndex)
printf("failed.\n");
cout<<"result: "<<resultIndex<<endl;
delete[] next;
}
// 空格在句子中间
void Test1()
{
string s = "aabcabcebafabcabceabcaefabcacdabcab";
string p = "abce";
Test("Test1", s, p, 4);
}
int _tmain(int argc, _TCHAR* argv[])
{
Test1();
return 0;
}
未优化next的版本,好记忆,但是不优化
class Solution {
public:
void GetNext(const char* str, int size,int* next)
{
if(!str || !next || (size<= 0))
<span style="white-space:pre"> </span>return;
<span style="white-space:pre"> </span>next[0] = -1;
<span style="white-space:pre"> </span>int jump = 0;
<span style="white-space:pre"> </span>int pre = 0;
<span style="white-space:pre"> </span>for(int i = 1; i < size; ++ i)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>pre = i-1;//实际需要知道的是i-1位置为结束点的最长前缀后缀匹配情况
<span style="white-space:pre"> </span>jump = next[pre];//记录下i-1位置的next值,next值得定义是前一个位置为结束点的最长前缀后缀匹配长度,即当前点若失配可以跳到的点
<span style="white-space:pre"> </span>while((jump > -1) && str[jump] != str[pre] )//这一步是如果jump不是-1,且jump位置值与pre位置值不等,jump接着往前面跳
<span style="white-space:pre"> </span>jump = next[jump];
<span style="white-space:pre"> </span>if(jump < 0)//如果jump跳到-1,那么next[i] = 0;
<span style="white-space:pre"> </span>next[i] = 0;
<span style="white-space:pre"> </span>else // if(str[jump] == str[pre]),当前next[i]计算i-1位置的最长前缀后缀匹配长度,就是jump+1
<span style="white-space:pre"> </span>next[i] = jump + 1;
<span style="white-space:pre"> </span>}
}
int KMP_Search(char const* src,int slen,char const* pstr,int plen,int const* next,int pos)
{ if(0 == slen && 0 == plen)
return 0;
if(0 == plen)
return 0;
int ans = -1;
int i = pos;
int j = 0;
while(i < slen && j < plen )
{
if(j == -1 || src[i] == pstr[j])
{
++ i;
++ j;
}else
j = next[j];
if(plen == j)
ans = i - plen;
}
return ans;
}
char *strStr(char *haystack, char *needle) {
int hlen = strlen(haystack);
int nlen = strlen(needle);
int* next = new int[nlen];
GetNext(needle,nlen,next);
int result = KMP_Search(haystack, hlen, needle, nlen, next, 0);
delete[] next;
if(-1 == result)
return NULL;
else
return (char*) haystack+result;
}
};
优化next数组
void GetNext(const char* str, int size,int* next)
{
next[0] = -1;
int i = 0;
int j = -1;
while(i < (size-1))
{
if(j == -1 || str[i] == str[j]) // 要么是j=-1起始情况,要么已经判断过的,已经求出next[i]的值再判断一遍,相等往下走
{
++ j;
++ i;
if(str[j] == str[i]) // 如果下一个位置相等,在已经确保前一个位置相等的情况下往后移动
next[i] = next[j];
else
next[i] = j; // 不等的话,j保存的就是前一个位置的最长前缀后缀长度
}
else
j = next[j];
}