C语言实现KMP算法和个人理解
Last updated on a year ago
以下内容皆为个人理解,可能存在不足或错误,请注意辨识。同时KMP不止一种实现方法
什么是KMP算法
KMP模式匹配算法是一种用来查找字符串的算法,由K,M,P(首字母)三位大佬提出,是一种朴素模式匹配算法更高效的方法。能有效缩短时间。
KMP算法与朴素算法比较
朴素算法,是一种很直观的算法,我们定义一个i和j,两个字符串s和t,s为主串,t为要查找的子串,i是指向s某个位置的指针,j同理指向t。
1 |
|
接着将子串与主串的各自元素进行比较,若相同则i,j指针后移继续比较,直到j遍历完子串,说明完全相等,返回i-j,就是子串在主串的位置。而若是在中途出现不匹配的,则将j指向重新指向头部,i移动到i-j+1的位置,重新遍历。
1 |
|
也就是说,朴素算法出现某个元素对不上时,需要将指针回滚,这样原本遍历过的元素又要重新遍历一次,而KMP算法就是一种只向前的算法,将遍历过的元素利用起来。
举个例子
1 |
|
当我们比较到第5个元素时,发现s[4]与t[4]对不上,如果是朴素算法,我们接下来就是从s[1]与t[0]开始重新比较,但是我们可以看到
c的前面元素是abab,前两个和后两个是一样的,同时主串也是abab,也就是说,我们可以跳过子串的前2个元素,因为它们和主串的3,4元素是一样的,所以不必比较。也就是直接比较s[4]与s[2]。
像这种ab ab称为公共前后缀,比如ab efg ab,它们的最长公共前后缀就是ab,有多长,我们就可以跳过多少个元素。那么我们要怎么得出这个最长公共前后缀呢?
我们可以建立一个next数组,将每个部分的最长公共前后缀记录。如:
1 |
|
对应的next数组为
1 |
|
解释一下:a 只有一个 最长公共为0,ab没有公共 为0, aba最长公共为1, abab最长公共为2, ababa最长公共为3(aba), ababaa最长公共为1(a)。
就是从第一个元素开始不断往后扩展,每扩展一次判定一次最长公共前后缀。next就是用于记录每次扩展后的最长公共前后缀。那么next如何利用到KMP算法呢?
KMP算法C语言实现
我们前面说了,在对比s和t中的元素时,若出现不等于的情况,可以直接跳过最长公共前后缀个元素,接着比较。s=“ababbaa” t=“ababc”。我们对比到第5个元素时,发现不相同,我们就看next数组的第4(就是5-1)个元素,它的值是2,说明前面这些元素最长公共前后缀是2,也就是说,我们可以跳过t的前2个元素,直接从t的第3个元素对比。具体代码实现为:
1 |
|
创建next数组
1 |
|