尊重产权,转载请注明出处。
ex:找一个单词在一篇文章中的定位 问题 :这种子串的定位操作
通常叫做 串的模式匹配。
ex 我们要从 goodgoogle 中 找 google 这个单词。
朴素的方法是:
1、取子串的第一个字符叫做子首,主串 向后查找,
直到找到第一个与子首相等的字符叫做主首;
2、子首后移一位,主首后移一位,再次比较(重复此过程)
要是直到查找了n次(n = 子串长度),仍然是次次对应相等,
说明子串就是主串真正的子串。
3、比如:
主串:goodgoogle;
子串:google;主串一开始与子串比较,子串比较到 g-d 发现不相等了,指向主串的指针退回到第二个字符o再重复2过程,
ex-2 : (设 n 为主串长度,m 为子串长度):
主串:00000000000000000000000000000000000000000001 n=44
子串:0000000000000000001 m= 19;
需要比较的次数约为:(n-m)*m (比较简单)
其实这是完全没有必要的,因为 当比较到 g-d 时候,
我们就能知道前面的六个字符肯定都不符合,
根本不需要退回到主串的第二个字符重新搜索
那,有人会问,干嘛非要讨论这种极端情况呢?
不,其实真的很有必要!
因为当m 越小,出现这种低效匹配的概率越高,
而若当m 越大,所导致的后果也就越严重。
不过,蛮力算法也并不是一无是处,比如在实际情况如搜索引擎里,
n是对应着需要搜索的库,m是用户输入的关键字,
n相对m来说是远远大于m的,所以O(n-m+1)*m 也等于 O(n),
极端情况的概率也就变得很小了。
*************************KMP讲解:****************************
比如:比较 abcdefgab 和 abcdex
仔细观察发现:子串的首字符a 与其后的bcdex 都不相等,
那么对于主串abcdefgab 的 与子串对应相等的前五位而言已经失去了比较的意义。主串只需要直接跳转到f 开始比较就行。
那么主、子串要是这样:
S = abcabcabx
T = abcabx 观察到子串中T1 = T4, 这种情况怎么办呢?
可以确定S2 S3肯定是不用再次比较了,所以T只需要与S4 S5 对齐即可。
子串如何滑动与主串是没有关系的,因为出现失配的前面 肯定都是匹配的,
所以指向主串的计数变量 i 不动,指向模式串(子串)的计数变量 j 会根据next 来确定滑动距离。
下面我们就以失配前匹配的那一段前缀来构建next[ ]数组以期确定下一次子串滑动的方向
那么next 数组究竟启什么作用?
返回失配位之前的最长公共前后缀!
具体来讲,KMP算法想要解决的主要矛盾是子串的自匹配所造成的重复冗余。
↑ 其中一律取 0 :就是从模式串的第一个字符开始 重新比较呗,
模式串中 没有重复的部分,那我们的KMP 也就无用武之地了。
说了这么多,那如何构建一个next[]数组呢? ↓
<<<<<<<<<<代码君>>>>>>>>>>>
int main() {
int next[10]; int pos = 0;
char T[MAXSIZE],S[MAXSIZE];
printf("Please input the main string and the model string \n");
while(scanf("%s%s",S,T)) {
Getnext(T,next);
int result = KMP(S,T,pos,next);
if(result)
printf("We found it :%d \n\n",result);
else
printf("NO FOUND!v\n\n");
}
system("pause") ;
return 0;
}
/* 在主串 S 的第 pos 个位置开始查找子串 T,返回模式串在主串中的位置*/
int Getnext(char *T,int next[]) {
int j = 0 , k = -1;int tlen = strlen(T);
next[0] = -1;
while( j < tlen) {
if(k == -1 || T[j] == T[k] ) {
j++;
k++;
next[j] = k;
} else
k = next[k];
}
}
int KMP(char *S,char *T,int pos,int next[]) {
int i = pos - 1;
int j = 0;
int slen = strlen(S);
int tlen = strlen(T);
while(i < slen && j < tlen) {
if(j == -1 || S[i] == T[j]) {
i++ ;
j++ ;
} else
j = next[j];
}
if(j >= tlen)
return i - tlen + 1;
else
return -1;
}