KMP 算法,search 子串

网上看了好多关于KMP算法的,但是都是看的不清不楚的,用了好多术语,不明白,后来自己根据结果倒推了过程,不知对不对,

暂时先记下来,

 

KMP算法,需要预先处理子串,然后建立一个int类型next数组(名字无所谓,主要是存储一些关于子串的信息),这里有几点要注意:

 

   next数组计算方法(假定j为数字下标,j >= 1)

      j = 1时, next[j] = 0, 这个是必定的,所有的next子串模式数组next[1] 都是0, next[0]这个弃之不用,

                   当然只是在下标的范围上不用,实际的数组空间我们还是要用的,也就是说,我们算法中的j值于实际的下标之间有

                                下标 = j - 1

                   的换算关系。

 

      j = 2时, next[j] = 1, 这个也是定死的,但仍你按后边的公式也可以推出这个的值,

     

      j > 2时,   next[j] 的值为

                   j位置前紧邻的字符串与子串第一个字符开始最大的相同子串数+1。这句是我从网上copy 来的,看不懂,但是我觉着应该是这样的:

                   j位置前紧邻的字符与子串第一个字符开始最大的相同字符数+1,

 

我们举个例子说明:

     比如有子串: abaabcac,  它的next模式数组应该是0,1,1,2,2,3,1,2, 我们来看下是怎样得来的,

     第一位是0,第二位是1,这是定死的,所以有0,1,

 

     我们看第三位,第三位对应的字符是a,注意我们的下标从1,开始:

                  abaabcac

        他前边的字符是b,b对应的next值是1,所以,我们从子串的一个字符开始比较,

        因为子串第一个字符是a,所以b没有相同的字符,则next[3] = 0 + 1,

    

     我们看第四位,对应的字符是a,
                  abaabcac

        它前边的字符是a,并且next[3] = 1, 所以我们从子串的第一位开始比较, a == a, 所有有一个字符相同,所有next[4] = 1 + 1,

 

     我们看第五位,对应的字符是b,

                  abaabcac

        他前边的字符是a,对应的next[4] = 2, 所以从第二位开始比较,a != b, 不同,要向前与第一位比较,a == a, 有一个字符相同,所有

        next[5] = 1 + 1, 其实这里可以取得前一个字符的next值,

                                 n = next[j - 1],  此处 n = 2, 然后在比较指针向前移动时,n 相应 - 1, 比如此处,在a != b是, 要与前一位比较

                                 则n 要 -1,

 

      我们看第六位,对应的字符是c,

                   abaabcac

 

         他前边的字符是b,对应的next[5] = 2, 所以从第二位开始比较,b == b, 所以, next[6] = next[5] + 1,

    

      我们看第七位,对应的字符是a,,

                   abaabcac

         他前边的字符是c,对应的next[6] = 3, 所以从第三位开始比较,

                                定义 n = next[6] = 3

                                 a != c,

                    所有要与第二位再次比较,同时n = n -1;

                                 b != c,

                    与第一位比较,n = n -1,

                                 a != c,

                     所以此位next[7] = 0 + 1

      我们看第八位,对应的字符是c,

                    abaabcac

           他前边的字符是a,对应的next[7] = 1, 所以于第一位比较 a == a,

           所以 next[ 8] = 1 + 1 = 2,

 

所以最终的next 数字序列是: 0,1,1,2,2,3,1,2

 

 然后我们看比较过程,这里就比较简单了:

 

                  

比较方法:

1.当S[i]=P[j],则:i++,j++;

2.当S[i]!=P[j],如果此时j!=0,则j=next[j],再继续比较;

如果j=0 则i++,j++,再继续比较

         

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

void

 

 

 

parseNextVector(string &substr, vector<int> &nextVec

)

{

 

 

int j = 1;

 

 

nextVec.push_back(0); //pos 1; pos 0 never used.

 

 

j++;

 

 

nextVec.push_back(1); // pos 2;

 

 

j++;

 

 

for (int i = 3; i <= substr.length(); i++)

{

 

 

int j = i -1;

 

 

int x = nextVec.back();

 

 

while(1)

{

 

 

cout << substr[j - 1] << " " << substr[x - 1] <<endl;

 

 

if (substr[j -1] == substr[x - 1])

{

 

 

nextVec.push_back(x + 1);

 

 

break;

}

 

 

else

{

 

 

 

x--;

 

 

if (x == 0)

{

 

 

nextVec.push_back(1);

 

 

break;

}

}

}

}

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

int

 

 

kmpSearch(string& str, string& subStr, vector<int>& nextVec)

{

 

 

int j = 0;

 

 

int i = 0;

 

 

while(i < str.length())

{

 

 

cout <<str[i] << " " <<subStr[j] <<endl;

 

 

if (str[i] == subStr[j])

{

 

 

if (j == subStr.length() - 1)

{

 

 

cout << i << " " << j <<endl;

 

 

return (i - j);

}

 

 

j++;

 

 

i++;

}

 

 

else

{

 

 

j = nextVec[j];

 

 

j = j - 1;

 

 

if (j < -1)

{

 

 

cout << "error: " << j <<endl;

 

 

return -1;

}

 

else if (j == -1)

{

 

 

j++;

 

 

i++;

}

}

}

 

 

return -1;

}

 

 

原文章地址:

http://blog.sina.com.cn/s/blog_5f240fc40100cjgr.html

 

这里的比较代码很简单,我没仔细看,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值