KMP算法理解

来源:互联网 发布:正规网络兼职打字员 编辑:程序博客网 时间:2024/06/06 09:24

一、KMP是计算字符串T是否包含在字符串P中的

二、实现步骤:

1、首先根据字符串P,计算出当匹配x个字符时,第x+1不匹配时,应该偏移多少的数组:next;
2、进行扫描字符串T,如果匹配了字符,那么匹配个数递增,当发现有不匹配时,就按照步骤1中计算的next中的值,进行偏移;

三、如何计算next:

1、首先介绍什么叫前缀,后缀,真前缀,真后缀;

前缀:除了最后一个字符以外,一个字符串的全部头部组合
后缀:除了第一个字符以外,一个字符串的全部尾部组合。
真前(后)缀:真前(后)缀就是指不包含自身的前(后)缀
举例:字符串ababac

前缀:a,ab,aba,abab,ababa
后缀:c,ac,bac,abac,babac
真前缀:a,ab,aba,abab
真后缀:c,ac,bac,abac

2、计算next数组的方法:

前缀数组next[j]是指某个字符串的最长真后缀同时也是它的前缀的子串长度。
举例:字符串ababc

a -> 0
ab -> 0
aba -> 1
abab -> 2
ababc -> 0

从上面可以看出,按照这个计算出来的next其实就是我们想要的;next[j]可以表示成,当字符串已经匹配到j时,第j+1个不匹配的话,我们就可以从字符串P的第next[j]个开始继续与字符串T进行匹配;

三、代码:

#include <iostream>#include <string>using namespace std;int arr[20] = {0};//这个就是文章中的next值void kmp_match(string t, string p){    int q = 0; //匹配到了p中的第几个字符    int k = 0;    for (unsigned int i = 0; i < t.length(); ++i)    {        //这里注意,发现有不匹配的,下一次进行匹配时,就不是从p[0]开始        //而是从p[k]开始,因为我们已经计算出偏移了,k之前的已经是匹配得了        while ( q>0 && t[i] != p[k] )        {            q = arr[q];            k = q;        }        if (t[i] == p[k])        {            q = q+1;            k = k + 1;        }        if (q == (p.length())) //已经全部匹配        {            cout << "is match all" << endl;            return;        }    }    cout << "is match failed" << endl;    return;}/*计算next值*/void compute_prefix(string str){    int len = str.length();    int q = 0;    int k = 0;    arr[1] = 0;    for (q = 1; q < len; ++q)    {        //如果发现有不匹配的,还要继续回退        while (k>0 && str[k] != str[q])        {            k = arr[k];        }        if (str[k] == str[q])            k = k + 1;        arr[q+1] = k;    }    for (unsigned int i = 1; i <= str.length(); ++i)    {        cout << arr[i] << endl;    }}void main(){    string p= "ababaca";    string t = "bacbababaabcbababaca";    compute_prefix(p);    kmp_match(t, p);    getchar();}
0 0
原创粉丝点击