该博客仅为博主初学KMP算法两天之下的个人理解,供日后复习使用,同时也希望能够帮助到其他和博主有相同问题的同学。
背景:每次匹配遇到遇到不匹配项是不必从头开始匹配(模式串仅移动一位)而是直接跳过计算好的位数,从模式串某一位开始匹配(该位前面部分一定已经与主串匹配),该博客将分为KMP算法以及失效函数的计算两部分。
概念介绍:
主 串——待匹配的串,长度更长,用T表示。
模式串——去与主串匹配的传,长度更短,用P表示。
失效函数用法——下一次匹配从模式串第f[j-1]+1位开始
一、失效函数
介绍:在模式串于主串不匹配时,模式串的指针应该移动到第几位,而保证此位之前的部分一定与主串匹配,而不用再一位一位移动主串。因此失效函数是针对模式串P而言,某一位与模式串串头开始的相同部分,并记录在失效数组 f 中。
原理:串p的第j位f(j)即是 将整个串p前k个字符与第j位处匹配,p[0~k]恰恰与p[j-k~j]匹配,如在下图的j=4,p[0~1]=p[3~4],即f(j)=1。
失效数组示例:
匹配过程示例:
失效函数具体代码:
注:此处失效函数代码不是最简洁的,具体可参见什么是KMP算法(详解)_攻城狮百里的博客-CSDN博客_kmp算法
代码解析:失效函数就是计算模式串与主串匹配时跳过的位数,用数组f存放。
一定注意:失效函数fail是针对模式串p计算
① f[0] = -1初始化数组第一位,理解为 如果模式串第1个匹配失败则仍然从串头开始匹 配,抵消f[x-1]+1的+1。
② 中间的while循环:求 i 的值,i 指的是到第 j 位前一位重复的个数(数组f的f[ j -1]值)
i 此时对应的是是第 j 位前面几位和串头相同的部分,那么第 j 位只会有两种情况.
⑴ 和 i +1位相同,则模式串第 j 个位置与串头i + 1相同,那么f[ j ] = f[j - 1] + 1,进入下 方if 完成+ 1即可。
⑵不相同,易知无法保证 j 的前n位与串头前n位完全一致。f[ i ]是将第 j - 1的数组值作 为下标,若 i 小于0则忽略,否则 i = f[ i ],i即移动到串头,再看此处是否有p [ i + 1] = p [ j ],做类似操作,类似于递归,直到 i 小于0。
③ 最下面的对f[j]赋值的if else:若满足p [ i + 1] = p [ j ],则是直接为 i + 1,否则为-1(不 与开头有任何重合)
注: f[ j ]为-1,表示此位需要从开头匹配。因为调用到f[ k ] 的其实是f[ k + 1] (见下),所以如果 第k位与串头不相同,就无法做到完全相同,因此只能 是-1。
二、匹配函数
代码解析 :匹配作用是比较模式串和主串,成功返回主串中相同部分的起始位,失败返回-1
length: 分别求出模式串和主串的串长。
pos : 下标,分别访问模式串和主串。
① while循环条件:两串都未到末尾,即结束条件为,模式串末尾(匹配成功),以及主串末尾(匹配失败)。
② 第一个if判断条件: 如果某一位相等,即pat[ j ] = main_str[ i ],则指针同时移动指向下一位,继续循环比较
③ 第二个if判断条件:如果某一位不相等,且是模式串第一位就不相等,无法调用失效数组f(下标将为-1非法),模式串指针仍然在第一位,主串指针后移一位,下一次比较
④ else : 某一位匹配失败但不是模式串第一位,读取失效数组,将该位以前一定与主串匹配的部分跳过,移动到待匹配的模式串处。调用失效数组的下标是pos_pat - 1是因为 : 第pos_pat前的几位都与主串匹配,而失效数组 f 记录的是某一位与模式串(自己)重合的位数,因此可以保证移动之后,串头与pos_pat之前相同,而pos_pat之前与主串相同。
最后读取match的返回值即可,但在调用match的时候需要先调用fail并传入失效数组 f ,也可以将两个函数合并,在match中调用fail。