学习KMP

来源:互联网 发布:淘宝客优惠券宣传海报 编辑:程序博客网 时间:2024/05/17 06:11

 因为在题目时遇见一个有关KMP的题目,于是开始学习KMP,说实话,很久以前就曾经学习过,不过在挣扎了几个小时还是没有思路的情况下,我放弃了,现在决定好好学习,这篇博客是我第一篇博客,旨在记录自己的学习过程,写得也不是很好,可能对其他人没有帮助,但我主要是想记录这个过程,大家看的时候,有什么错误请帮忙指出来,在此谢过了。

一、传统的字符匹配

T:ba a b a a b a b

P:ab a b b != a,P向右移   

T:b aa b a a b a b

P:   ba b a != b, P向右移

T:b a a b aa b a b

P:      ba b a != b, P向右移

T:b a ab a a b a b

P:b ab b!= a, P向右移

T:b a a b aa b a b

P:b a ba != b, P向右移

T:b a a b a a b a b

P:b a b匹配成功

这种匹配方式很简单,代码也十分容易写

int BFMatch( string& t, string& p ){int i,j;i = 0;j = 0;while( i < t.size()  ){if( t.at( i ) == p.at( j ) ){++i;++j;}else {j = 0;++i;}if( j == p.size() - 1 )return i - p.size() + 1;}return -1;}

这种匹配耗费的时间O( M * N ), M和N,分别是模式串和目标串的长度。

二、KMP算法

KMP算法中的next数组的含义:next[ i ] = k, 表明 在第i位置的字符 前面,连续k个字符,与开头k个字符相同

举个例子:

     下标:0  1  2  3  4  5

    字符串P:a  b  a  b  a  b

    next:-1  0   0  1  2  3

next[ 0 ] = -1,是个结束标志(网上对于next数组有几种不同的标法,本质都一样)next[ 1 ] = 0,都可以定下来的

next[ 2 ] = 0, P[ 2 ] = a 前面 有 0 个字符 与 开头 0 个字符相同

next[ 3 ] = 1, P[ 3 ] = b, 前面有 1 个字符(a) 与 开头1个字符相同(a)

next[ 4 ] = 2, P[ 4 ] = a, 前面有 2 个字符(ab)与开头2个字符相同(ab)

next[ 5 ] = 3, P[ 5 ] = b, 前面有 3 个字符(abc)与开头3个字符相同(abc)

KMP算法,就是通过这个next数组来做到快速匹配的,那为什么呢?

比如一开始的例子:

T:a a b a a b a b

P:a b a b

next:-1 0 0 1

比如匹配到

发生了不匹配,P要进行移动,传统匹配是移动一位的,KMP根据next数组的值进行移动,next[ 3 ] = 1, 那么这样移动也就是说,P右移了两位,可以这样移动是因为

T:b a a b a a b a b

 

P:     a b a b这三部分是一样的,所以移动两位时,可以保证 重新匹配 原本不相同的那个位置时,这个位置前面的字符是相同的。

void get_next( string& p, int next[] ){int i,j;next[ 0 ] = -1;i = 0;j = -1;while( i < p.size() - 1 ){if( j == -1 || p[i] == p[j] ){next[ ++i ] = ++j;}else j = next[j];}}

}

0 0
原创粉丝点击