16 - 12 - 20 KMP算法 模式匹配 终极奥义!

来源:互联网 发布:3dmax有没有mac版 编辑:程序博客网 时间:2024/05/17 23:00

尊重产权,转载请注明出处。

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;}
1 0
原创粉丝点击