赞
踩
从主串test 和模式串pattern 的第一个字符开始,将两字符串的字符一一比对,如果出现某个字符不匹配,主串回溯到第二个字符,子串回溯到第一个字符再进行一一比对。如果出现某个字符不匹配,主串回溯到第三个字符,子串回溯到第一个字符再进行一一比对…循环一直到子串字符全部匹配成功。
第一次:不匹配
第二次:主串从第2个字符,模式串从头开始,直到b与c不匹配
第三次:主串从第3个位置开始,模式串从头开始,a与c不匹配
第四次:主串从第4个位置开始,模式串从头开始,匹配成功
朴素模式匹配的缺点:
当主串与模式串能部分匹配时, 主串的扫描指针i经常回溯,导致时间开销增加。
当字串与模式串不匹配的时候,主指针不需要再次回溯,只需要调整模式串的位置
例如:
当扫描到 a , f 不匹配时,如果是朴素模式匹配那么 i指针会退到第二个位置,j指针会退到开头位置
而如果是kmp算法,会调整 j 的位置,而不使 i 指针回退
实现这个功能那就必需要一个next数组
kmp算法最主要的就是next数组
next数组作用:
next[i]的值表示下标为i的字符前的字符串最长相等前后缀的长度。
表示该处字符不匹配时应该回溯到的字符的下标
(1)初始化 i ,j,next[0]。i 指针指向前缀的最大长度,j 指针指向后缀的最大长度
(2)当i,j指针指的元素不相等时
(3)当i,j指针指的元素相等时
(4)next数组赋值或调整 j 指针的位置
这里初始化为next[0]=-1,j=0,k=-1,之后得到 next[i] 数组就是对应的值
如果初始化为next[1]=0,j=1,k=0,则需要初始数组空一格位置
- void GetNext(char* p, int next[])
- {
- int pLen = strlen(p);
- next[0] = -1;
- int k = -1; //k指向前缀
- int j = 0; //j指向后缀
- while (j < pLen - 1)
- {
- //p[k]表示前缀,p[j]表示后缀
- if (k == -1 || p[j] == p[k])
- {
- ++k;
- ++j;
- next[j] = k;
- }
- else
- {
- k = next[k]; //回退因为如果此时最大前后缀不满足,则继续看前一个元素的最大前后缀值
- }
- }
- }
此时i,j指的元素不相同,需要缩小最大前后缀的长度:j=next[j]
当i<length-1时退出循环,每次字符的前面匹配的字符的最大前后缀均以求出
- int KmpSearch(char* s, char* p,int next[])
- {
- int i = 0;
- int j = 0;
- int sLen = strlen(s);
- int pLen = strlen(p);
- while (i < sLen && j < pLen)
- {
- //①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++
- if (j == -1 || s[i] == p[j])
- {
- i++;
- j++;
- }
- else
- {
- //②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]
- //next[j]即为j所对应的next值
- j = next[j];
- }
- }
- if (j == pLen)
- return i - j;
- else
- return -1;
- }
测试:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。