wiki简介
Knuth-Morris-Pratt算法
在计算机科学中,Knuth-Morris-Pratt 字符串搜索算法(或KMP算法)通过观察当发生不匹配时,单词本身包含足够的信息来搜索W
主“文本字符串”中“单词”的S
出现。确定下一场比赛的开始位置,从而绕过对先前匹配的角色的重新检查。
该算法由Donald Knuth和Vaughan Pratt于1970年构思,并由James H. Morris独立构思。三者于1977年联合出版。[1] 独立于1969年,Matiyasevich [2] [3]发现了一种类似的算法,由二维图灵机编码,同时研究二进制文件中的字符串模式匹配识别问题字母。这是第一个用于字符串匹配的线性时间算法。
内容
背景
字符串匹配算法想要m
在字符串S[]
中找到与搜索词匹配的起始索引W[]
。
最简单的算法,称为“ 暴力 ”或“朴素”算法,是在每个索引处查找单词匹配m
,即搜索字符串中的位置,即S[m]
。在每个位置m
,算法首先检查被搜索的单词中第一个字符的相等性,即S[m] =? W[0]
。如果找到匹配,则算法通过检查单词位置索引的连续值来测试被搜索单词中的其他字符i
。该算法检索W[i]
被搜索单词中的字符并检查表达式的相等性S[m+i] =? W[i]
。如果所有连续字符W
在位置匹配m
,则在搜索字符串中的该位置处找到匹配。如果索引m
到达字符串的末尾然后没有匹配,在这种情况下,搜索被称为“失败”。
通常,试用检查会很快拒绝试用比赛。如果字符串是均匀分布的随机字母,那么字符匹配的机会是26中的1。在大多数情况下,试验检查将拒绝首字母的匹配。前两个字母匹配的可能性是26 2中的 1(676 中为1 )。因此,如果字符是随机的,那么搜索S[]
长度为k的字符串的预期复杂度是k个比较或O(k)的顺序。预期的表现非常好。如果S[]
是100万个字符并且W[]
是1000个字符,那么字符串搜索应该在大约104万个字符比较之后完成。
预期的表现无法保证。如果字符串不是随机的,那么检查试验m
可能需要进行许多字符比较。最糟糕的情况是,除了最后一个字母之外,两个字符串都匹配。试想一下,该字符串S[]
由1个万字是所有的一个,和这个词W[]
是999个一个字符在最后终止乙字。现在,简单的字符串匹配算法将在每个试验位置检查1000个字符,然后拒绝匹配并推进试验位置。简单的字符串搜索示例现在将进行大约1000个字符比较,时间为100万个位置,进行10亿个字符比较。如果长度W[]
是n那么最坏情况的表现是O(k · n)。
与直接算法相比,KMP算法具有更好的最坏情况性能。KMP花一点时间预计算表(大小的顺序W[]
,Ø(ñ)),然后它使用表做有效率的搜索字符串的Ô(ķ)。
不同之处在于KMP利用了直接算法所没有的先前匹配信息。在上面的示例中,当KMP在第1000个字符(i
= 999)上看到试验匹配失败时,因为S[m+999] ≠ W[999]
它将增加m
1,但它将知道新位置的前998个字符已经匹配。KMP匹配999点甲第1000次字符(位置999)发现不匹配前的字符。推进试验比赛的位置m
会抛弃第一个A,所以KMP知道有998个A字符匹配W[]
且不重新测试; 也就是说,KMP设定i
KMP在预先计算的表和两个状态变量中保持其知识。当KMP发现不匹配时,该表确定KMP将增加多少(变量m
)以及它将在何处恢复测试(变量i
)。
KMP算法
搜索算法的示例
为了说明算法的细节,考虑算法的(相对人为的)运行,其中W
=“ABCDABD”和S
=“ABC ABCDAB ABCDABCDABDE”。在任何给定时间,算法处于由两个整数确定的状态:
m
,表示S
预期匹配W
开始的位置,i
,表示当前考虑的字符的索引W
。
每个步骤中的算法进行比较S[m+i]
与W[i]
和增量i
如果它们是相等的。这在运行开始时被描述为
1 2
m:01234567890123456789012
S:ABC ABCDAB ABCDABCDABDE
W:ABC D ABD
i:012 3 456
该算法比较W
“并行”字符的连续字符,如果它们匹配则S
通过递增从一个字符移动到下一个字符i
。但是,在第四步S[3] = ' '
中不匹配W[3] = 'D'
。S[1]
我们注意到,'A'
在第1和第2位之间没有发生,而不是再次开始搜索S
; 因此,在检查了所有这些字符之后(并且知道它们与相应的字符匹配W
),没有机会找到匹配的开始。因此,算法集m = 3
和i = 0
。