KMP算法

在计算机科学中，克努斯-莫里斯-普拉特字符串查找算法（，简称为KMP算法）可在一个字符串codice_1内查找一个-{zh-hans:词; zh-hant:字;}-codice_2的出现位置。一个词在不匹配时本身就包含足够的信息来确定下一个匹配可能的开始位置，此算法利用这一特性以避免重新检查先前配对的字符。
这个算法由高德纳和沃恩·普拉特在1974年构思，同年詹姆斯·H·莫里斯也独立地设计出该算法，最终三人于1977年联合发表。
查找过程.
以codice_2=codice_4，codice_1=codice_6为例说明查找过程。查找过程同时使用两个循环变量codice_7和codice_8：
图示如下：
 m: 
 S: 
 W: 
 i: 
从codice_2与codice_1的开头比较起。比对到codice_16时，发现codice_17与之不符。接著并不是从codice_18比较下去。已经知道codice_19不与codice_20相合。因此，略过这些字元，令codice_21以及codice_22。
 m: 012
 S: ABC
 W: 
 i: 
可以看出，第一位codice_23直接不符合codice_16，因此往后移动一位至codice_25继续与codice_22进行比较。
 m: 0123
 S: ABC 
 W: 
 i: 
如上所示，检核了codice_27这个字串。然而，下一字符便不相合。可以注意到，codice_28在codice_27的头尾处均有出现。这意味著尾端的codice_28可以作为下次比较的起始点。因此，令codice_31，继续比较。图示如下：
 m: 01234567
 S: ABC ABCD
 W: 
 i: 
于codice_32的地方，又出现不相符的情况。类似地，令codice_33继续比较：
 1 
 m: 01234567890
 S: ABC ABCDAB 
 W: 
 i: 
这时，codice_34不与codice_35相同，但是已匹配部分codice_27亦为首尾均有codice_28，采取一贯的作法，令codice_38和codice_39，继续搜寻。
 1 
 m: 012345678901234
 S: ABC ABCDAB ABCD
 W: 
 i: 
找到完全匹配的字串了，其起始位置于codice_40的地方。
部分匹配表.
部分匹配表，又称为失配函数，作用是让算法无需多次匹配codice_1中的任何字符。能够实现线性时间搜索的关键是在主串的一些字段中检查模式串的"初始字段"，可以确切地知道在当前位置之前的一个潜在匹配的位置。换句话说，在不错过任何潜在匹配的情况下，"预搜索"这个模式串本身并将其译成一个包含所有可能失配的位置对应可以绕过最多无效字符的列表。
对于codice_2中的任何位置，都希望能够查询那个位置前（不包括那个位置）有可能的codice_2的最长初始字段的长度，而不是重新从codice_20开始比较整个字段，这长度就是查找下一个匹配时回退的距离。因此codice_45是codice_2的可能的"适当"初始字段同时也是结束于codice_47的子串的最大长度。使空串长度是0。当一个失配出现在模式串的最开始，这是特殊情况（无法回退），设置codice_48，在下面讨论。
创建表算法示例.
以codice_49为例。以下将看到，部分匹配表的生成过程与前述查找过程大同小异，且出于类似原因是高效的。
首先，设定codice_48。为求出codice_51，必须找到一个codice_52的真后缀（真后缀指不等于原串的后缀）兼codice_2的前缀。但codice_52没有真后缀，所以设定codice_55。类似地，codice_56。
继续到codice_57，注意到检查所有后缀有一个捷径：假设存在符合条件的前后缀，两者分别为codice_58，则必有codice_59。由于codice_60亦是codice_2的真前缀，上一步必然已经得到codice_62（而有codice_56，说明假设不成立）。一般地，遍历到每个字符时，只有上一步已经发现一个长为m的有效后缀，才需要判断有无长为m+1的后缀，而毋需考虑长为m+2、m+3等的后缀。
从而，不必考虑长为2的后缀，而唯独需要考虑的长度1亦不可行，故得到codice_64。
接下来是codice_65。基于同样的理由，需要考虑的最大长度为1，并且在codice_66这个情况中有效，回退到寻找的当前字符"之前"的字段，因此codice_67。
现在考虑下一个字符codice_68，使用这样的逻辑：如果曾发现一个子模式在上一个字符codice_69之前出现，继续到当前字符codice_70，那么在它之前它本身会拥有一个结束于codice_69合适的初始段，与事实相反的是已经找到codice_66是最早出现在结束于codice_69的合适字段。因此为了找到codice_70的终止串，不需要查看codice_69。因此codice_76。
最后到codice_65。下一个字符是codice_78，并且这也确实是codice_70。此外，上面的相同参数说明为了查找codice_35的字段，不需要向前查看codice_69，所以得出codice_82。
于是得到下面的表：
另一个更复杂和有趣的例子：
建立表算法的伪代码的解释.
上面的例子以最少的复杂步骤展示了组织这个表格的一般性方法。这么做的原理是对整体的搜索：大多数工作已经在检测到当前位置的时候做完了，剩下需要做的很少。略微复杂的一点是找到一个共同前后缀。这就需要有一些初始化的代码。
 algorithm "kmp_table":
 input:
 an array of characters, W (the word to be analyzed)
 an array of integers, T (the table to be filled)
 output:
 nothing (but during operation, it populates the table)
 define variables:
 an integer, pos ← 2 (the current position we are computing in T)
 an integer, cnd ← 0 (the zero-based index in W of the next &lt;br&gt;character of the current candidate substring)
 (the first few values are fixed but different from what the algorithm &lt;br&gt;might suggest)
 let T[0] ← -1, T[1] ← 0
 while pos &lt; length(W) do
 (first case: the substring continues)
 if W[pos - 1] = W[cnd] then
 let cnd ← cnd + 1, T[pos] ← cnd, pos ← pos + 1
 (second case: it doesn't, but we can fall back)
 else if cnd &gt; 0 then
 let cnd ← T[cnd]
 (third case: we have run out of candidates. Note cnd = 0)
 else
 let T[pos] ← 0, pos ← pos + 1
建立表的算法的效率.
建立表的算法的复杂度是formula_1，其中formula_2是codice_2的长度。
除去一些初始化的工作，所有工作都在循环中完成。为说明循环执行用了formula_1的时间，考虑codice_84和codice_85的大小。
因为codice_97，即在每一个阶段要么codice_84增加，要么codice_84的一个下界增加。故既然算法在codice_100时终止，此循环必然在最多formula_4次迭代后终止。因此建立表的算法的复杂度是formula_1。