串的匹配 (KPM算法由来引导)

前言:

引入 KPM 算法的前提是 , B-F算法中,匹配失败后不必完全从头再来 , 找到可以利用的信息 , 可以进行跳跃性匹配

下面 , 我们对字符串匹配的一些思路进行剖析:

开始匹配的操作 ,我们会让 目标串 s , 和 模式串进行对齐,就像如图所示:


 我们当然是从串 t 的头结点开始对比 

   对比 第一个元素 , 符合


然后对比第二个 元素符合


 对比第三个元素 , 不相等


此时 , 按照我们 B-F算法 , 不相等 , 我们就需要重新从 串 s 的第二个元素, 进行和 串 t 进行比较了  

如图 : 

但是 , 此时我们注意到 , 我们开头已经对比了 串 t 和 串 s 两个元素重合 , 并且他们互不相等 , 说明再次把串 t 的开头 和  串 s 的第二个元素是不明智的选择

因为 , 我们既然要寻找和串 t 相等的串 , 首先要保证的就是 , 串 t 的头结点要和串 s 元素先匹配上, 然后我们才能继续后续的对比 

我们现在前两个节点已经重合, 并且他们互不相同 , 就没必要再移动一位了重合比较了

所以 , 我们直接 将串 t 开头和 串 s 的第三个元素进行比较即可


我们接着对比 , a 相等 , b 相等 , c 相等 , a 相等 , 当比较到串 t 的第五个元素时 , b 和 c 不相等 ,

此时, 我们如果还采取 B-F算法当然也是可以的 , 逐个将 串t 和 对比初始位置后移的串 s 进行对比 ,

 


我想 , 上面的步骤有些是没必要的 , 因为我们此时分析 :

串 t 此时我们已经对比了五个元素 , 前 四个已经对比符合了 ,

我们现在第五个元素, 对比到了不同元素 , 我们能直接把对比过的字符串抛弃吗? 

意思就是说 , 我们能下定论, 已经对比过的字符, 不会再有可以匹配的子串了呢?

能直接如下图所示吗? 

聪明的我们, 会发现 , 我们就算对比重合过的字符 , 遇到不同的字符 , 我们也不能直接把 比较重合过的字符全部抛弃 , 除非对比过的字符互不相同 , 那 我们直接略过也没事 , 

但是如果, 我们对比过的字符 , 有和 串 t 头结点相等的节点 , 我们就不能略过了 

上图, 标蓝 部分 , 我们在我们在对比的时候已经对比过了 , 我们会发现  串 t 里面有两个头节点 , 那当我对比到 第二个头结点之后的一个节点的时候 , 我们如果发现不同字符 , 我们就可以把第二个头结点当作头结点, 然后后续接着让 串 t 的第二个节点和 串 s 进行比较


我们上面的意思就是 , 假如现在有一个

当串 s 和 串 t 元素进行比较时 , 当一个字符不匹配的时候 , 我们必然要让 串 t 开头 往后移动

但是逐个比较的话 , 有些节点是没必要比较的 , 如下图:

明明知道, 前五个字符两个串对比符合了, 并且五个字符互不相同 , 就没必要逐个错峰比较了,

直接跳过这五个元素 , 让 串 t 第一个元素和串 s 第五个元素进行比较

但是 , 有的情况 , 当比较到不同字符时 , 那个字符前面有和头结点相同的子串的话 ,我们就可以直接把 头结点子串的位置, 拉到 不同字符前面的头节点子串的位置 , 这样就不会错过重合的机会了.

如下图

经过上面的分析 , 我们得出, 如果要准确把握模式串 t 每个字符 比较到不同的字符的时候 ,应该跳到串 t 哪个字符再和 串 s那个元素进行比较 , 就需要找出每个字符前面的和头结点子串相等的子串 , 

那当子串有很多呢 ? 找哪一个呢?

我们就需要引入前缀串和后缀串 

作者能力有限 , 下一篇博客 ,转载大佬解析 ,我这里只做思路引导 . 

c代码:

#include <stdio.h>
#include "sqString.h"
void GetNext(SqString t , int next[])
{int j,k;j = 0;k = -1;next[0] = -1;while(j<t.length-1){if(k == -1 || t.data[j] ==t.data[k]){j++;k++;next[j] = k;}else{k = next[k] ;}}
}
//进行验证
int KMPIndex(SqString s, SqString t)
{int next[MaxSize],i=0,j=0;GetNext(t,next);while(i<s.length && j<t.length){if(j == -1 || s.data[i] == t.data[j]){i++;j++;}else{j = next[j];}}if(j >= t.length){return(i - t.length);}else{return(-1);}
}
int main()
{SqString s,t;StrAssign(s,"ababcabcacbab");StrAssign(t,"abcac");printf("s:");DispStr(s);printf("t:");DispStr(t);printf("位置: %d\n",KPMIndex(s.t));return 0;
}

串的匹配 (KPM算法由来引导)

前言:

引入 KPM 算法的前提是 , B-F算法中,匹配失败后不必完全从头再来 , 找到可以利用的信息 , 可以进行跳跃性匹配

下面 , 我们对字符串匹配的一些思路进行剖析:

开始匹配的操作 ,我们会让 目标串 s , 和 模式串进行对齐,就像如图所示:


 我们当然是从串 t 的头结点开始对比 

   对比 第一个元素 , 符合


然后对比第二个 元素符合


 对比第三个元素 , 不相等


此时 , 按照我们 B-F算法 , 不相等 , 我们就需要重新从 串 s 的第二个元素, 进行和 串 t 进行比较了  

如图 : 

但是 , 此时我们注意到 , 我们开头已经对比了 串 t 和 串 s 两个元素重合 , 并且他们互不相等 , 说明再次把串 t 的开头 和  串 s 的第二个元素是不明智的选择

因为 , 我们既然要寻找和串 t 相等的串 , 首先要保证的就是 , 串 t 的头结点要和串 s 元素先匹配上, 然后我们才能继续后续的对比 

我们现在前两个节点已经重合, 并且他们互不相同 , 就没必要再移动一位了重合比较了

所以 , 我们直接 将串 t 开头和 串 s 的第三个元素进行比较即可


我们接着对比 , a 相等 , b 相等 , c 相等 , a 相等 , 当比较到串 t 的第五个元素时 , b 和 c 不相等 ,

此时, 我们如果还采取 B-F算法当然也是可以的 , 逐个将 串t 和 对比初始位置后移的串 s 进行对比 ,

 


我想 , 上面的步骤有些是没必要的 , 因为我们此时分析 :

串 t 此时我们已经对比了五个元素 , 前 四个已经对比符合了 ,

我们现在第五个元素, 对比到了不同元素 , 我们能直接把对比过的字符串抛弃吗? 

意思就是说 , 我们能下定论, 已经对比过的字符, 不会再有可以匹配的子串了呢?

能直接如下图所示吗? 

聪明的我们, 会发现 , 我们就算对比重合过的字符 , 遇到不同的字符 , 我们也不能直接把 比较重合过的字符全部抛弃 , 除非对比过的字符互不相同 , 那 我们直接略过也没事 , 

但是如果, 我们对比过的字符 , 有和 串 t 头结点相等的节点 , 我们就不能略过了 

上图, 标蓝 部分 , 我们在我们在对比的时候已经对比过了 , 我们会发现  串 t 里面有两个头节点 , 那当我对比到 第二个头结点之后的一个节点的时候 , 我们如果发现不同字符 , 我们就可以把第二个头结点当作头结点, 然后后续接着让 串 t 的第二个节点和 串 s 进行比较


我们上面的意思就是 , 假如现在有一个

当串 s 和 串 t 元素进行比较时 , 当一个字符不匹配的时候 , 我们必然要让 串 t 开头 往后移动

但是逐个比较的话 , 有些节点是没必要比较的 , 如下图:

明明知道, 前五个字符两个串对比符合了, 并且五个字符互不相同 , 就没必要逐个错峰比较了,

直接跳过这五个元素 , 让 串 t 第一个元素和串 s 第五个元素进行比较

但是 , 有的情况 , 当比较到不同字符时 , 那个字符前面有和头结点相同的子串的话 ,我们就可以直接把 头结点子串的位置, 拉到 不同字符前面的头节点子串的位置 , 这样就不会错过重合的机会了.

如下图

经过上面的分析 , 我们得出, 如果要准确把握模式串 t 每个字符 比较到不同的字符的时候 ,应该跳到串 t 哪个字符再和 串 s那个元素进行比较 , 就需要找出每个字符前面的和头结点子串相等的子串 , 

那当子串有很多呢 ? 找哪一个呢?

我们就需要引入前缀串和后缀串 

作者能力有限 , 下一篇博客 ,转载大佬解析 ,我这里只做思路引导 . 

c代码:

#include <stdio.h>
#include "sqString.h"
void GetNext(SqString t , int next[])
{int j,k;j = 0;k = -1;next[0] = -1;while(j<t.length-1){if(k == -1 || t.data[j] ==t.data[k]){j++;k++;next[j] = k;}else{k = next[k] ;}}
}
//进行验证
int KMPIndex(SqString s, SqString t)
{int next[MaxSize],i=0,j=0;GetNext(t,next);while(i<s.length && j<t.length){if(j == -1 || s.data[i] == t.data[j]){i++;j++;}else{j = next[j];}}if(j >= t.length){return(i - t.length);}else{return(-1);}
}
int main()
{SqString s,t;StrAssign(s,"ababcabcacbab");StrAssign(t,"abcac");printf("s:");DispStr(s);printf("t:");DispStr(t);printf("位置: %d\n",KPMIndex(s.t));return 0;
}