/*
*
* KMP算法的学习【复杂度O(M + N)】 两个字符串的长度和
* Next数组的求法【核心】 + 思想: 指示主串的指针[i]不回溯,只是指示模式串的指针[j]发生回溯
*
* 例子:
* 主串S: ababcabcaabcbaabc
* 模式串T: ababcabababc
*
* 模式串对应的Next数组的值:
*
未改进前的Next值:
* Next值: 0 1 1 2 3 1 2 3 4 5 4 5
* a b a b c a b a b a b c
//有一种情况: 这种情况的话,那个得到Next值的方法就不好了...
//
// 主串S:aaabaaabaaabaaabaaaab
//模式串T:aaaab
//Next值: 01234
改进后的Next值:
* Next值: 0 1 0 1 3 0 1 0 1 5 1 3 //其实只是 比如第三个a的头上是1,那去找下T[1]是否等于a,如果等于a,那么就把自己的Next值和它相等.即0,其他的也如此!
* a b a b c a b a b a b c
* Next值的求法:【数组的第零个舍去】
需要一个求模式串Next数组的函数【计算机求Next值的过程是一个递推的过程】
(1)函数算Next值的分析:
已知: Next[1] = 0;
假设: Next[j] = k; 又有T[j] == T[k]
则 Next[j+1] = k+1; //Next[j] + 1;
若 T[j] != T[k]
则需要往前回溯,检查T[j] 是否和 T[Next[k]]相等,一直找到相等的字符为止,然后 Next[j] 就等于 Next[相等的这个字符] + 1;
算法代码实现: GetNext(char * ModelString, int & Next[]);
* (2)手动算Next[j]: [比较好理解Next数组的算法]
* 当j == 1时, Next[1] = 0;
* 当j前面有匹配的,取(最大的匹配字串的字符个数 + 1)作为Next[j]的值 (重: 是从当前j的位置往前面找相等的子串)
* 当除了上面两种情况外,其他的情况Next[j] = 1;
例:
a b a b c a b a b a b c
0
j == 1; 既字符串的第一个位置: 第一个a, Next[1] = 0;
j == 2; 字符串的第二个位置: 字符b, 分析,第二个字符前面只有一个字符a,所以没有匹配的重复字符子串,既 Next[2] = 1;
j == 3; 字符串的第三个位置: 字符a, 分析,第三个字符前面有两个字符 a b,a 和 b不相等,所以也是 Next[3] = 1;
j == 4; 字符串的第四个位置: 字符b, 分析,第四个字符前面有三个字符 a b a, 因为a 和 a 相等,所以 Next[4] = 1+1 = 2;
j == 5; 字符串的第五个位置: 字符c, 分析,第五个字符前面有四个字符 a b a b ,因为 ab 和 ab子串[ab长度为2]相等,所以 Next[5] = 2 + 1 = 3;
j == 6; 字符串的第六个位置: 字符a, 分析,第六个字符前面有五个字符 a b a b c,因为c和前面的子串中没有相等的,b c和前面也没有相等的,所以 Next[6] = 1;
.....
.....依次类推
*
*
利用Kmp和Next数组的运算,就是当 S[i] == T[j] 的时候 ++i, ++j;
当 S[i] != T[j] 的时候,回溯j,不能动i, j = Next[j]; //等于当前Next[j]的值
当 j == 0;//表示回溯到了第一个位置了,这个时候要把 i向后移动一位,而j = 0(默认不用这个数组的下标0的元素),所以也要++j, 再比较S[i] ? T[j]
*/
#include <stdio.h>
#include <string.h>
//为改进前的求Next函数
void GetNext(char * ModelString, int * next)
{ //求模式串ModelString的next值,并存入next数组中
int i = 1;
int j = 0;
next[1] = 0; //这个是已知的【默认都是这样】
int len = strlen(ModelString);
while (i < len)
{
if (j == 0 || ModelString[i] == ModelString[j])
{
++j;
++i;
next[i] = j;
}
else
j = next[j];
}
}
//改进后的求Next函数
void GetGoodNext(char * ModelString, int * next)
{
int i = 1;
int j = 0;
next[1] = 0; //这个是已知的【默认都是这样】
int len = strlen(ModelString);
while (i < len)
{
if (j == 0 || ModelString[i] == ModelString[j])
{
++j;
++i;
if (ModelString[i] != ModelString[j])
next[i] = j;
else
next[i] = next[j];
}
else
j = next[j];
}
}
int IndexKmp(char * MainString, char * ModelString, int Pos)
{
// 1<=Pos<=strlen(MainString)
int i = Pos;
int j = 1; //从第一个位置开始
int lenMainString = strlen(MainString);
int lenModelString = strlen(ModelString);
while (i<=lenMainString && j<=lenModelString)
{
if (MainString[i] == ModelString[j] || j == 0)
{
++i;
++j;
}
else
{
j = Next[j]; //把当前位置的Next值赋给j, Next数组可以做成全局变量,也可以作为参数传进来
}
}
if(j > lenModelString)
{ //匹配成功了,返回匹配字符串的第一个字符
return i - lenModelString;
}
else
{ //匹配不成功,返回0
return 0;
}
}
int main()
{
return 0;
}