在说KMP匹配算法之前,我们先来看看与它相近的另一种匹配算法,名曰“暴力匹配算法”
1.暴力匹配算法(设有如下的两组字符串)
第一位不匹配,则向右移动一位,得到如下的形式
B与A依旧不匹配,则继续往后移,当移到如下的形式时:
尽管之前的文本串和模式串已经分别匹配到了S[9]、p[5].但因为S[10]和p[6]不匹配,所以文本串会回溯到p[0].从而让是s[5]跟p[0]匹配(S[5]与p[0]肯定匹配失败,因为S[5] = p[1] = B P[0] = A.所以S[5] != P[0])得到如下结果:
然后又开始进行后移匹配。
这块的算法代码为:
if(S[i] == P[j]) { i++; j++; } else { i = i-j+1; j = 0; }
2.KMP匹配算法
相对于暴力匹配算法的改进是引入了一个跳转表nex[];
算法思路:
(1)假设现在文本串S匹配到i位置,模式串P匹配到j位置
(2)若j = -1,或者当前字符匹配成功(即S[i] == P[j])都令i++,j++继续匹配下一字符;
(3)若j != -1,且当前字符匹配失败(即S[i] != P[j]),则令i不变 j = next[j](当匹配失败时,模式串向右移动的位数为:失配字符所在的位置 - 失配字符所对应的nex值,即移动的实际位数为j - next[j](当前字符串中有多大长度的相同前缀后缀)),如下表:
模式串的单个子串 | 前缀 | 后缀 | 最大公共元素长度 |
A | 空 | 空 | 0 |
AB | A | B | 0 |
ABCD | A,AB,ABC | D,CD,BCD | 0 |
ABCDA | A,AB,ABC,ABCD | A,DA,CDA,BCDA | 1 |
ABCDAB | A,AB,ABC,ABCD,ABCDA | B,AB,DAB,CDAB,BCDAB(长度为2) | 2 |
ABCDABD | A,AB,ABC,ABCD,ABCDA,ABCDAB | D,BD,ABD,DABD,CDABD,BCDABD | 0 |
因此:
第一位都不匹配,直接将模式串不断向右移一位,直到模式串中的字符A和文本中的第5个字符A匹配成功
此时,匹配的字符数为6个,Next[j] = 2 ,j=6.所以:右移 j-Next[j] = 6-2 = 4个
Next[j] = 0 j = 2 所以:右移 2-0 = 2位
右移一位
然后继续右移4位
至此,文本串和字符串已经匹配成功
具体算法:
if(j == -1 || S[i] == P[j]) { i++; j++; } else { j = Next[j]; }