在这里我所要想说的比KMP算法高效的算法是Boyer-Moore算法。
在讲解Boyer-moore算法之前,在这里先回顾一下KMP算法。
比如说有一个字符串”BBC ABCDAB ABCDABCDABDE”,我想知道,里面是否包含另一个字符串”ABCDABD”。大部分情况下我们会使用KMP算法去解:
首先,字符串”BBC ABCDAB ABCDABCDABDE”的第一个字符与搜索词”ABCDABD”的第一个字符,进行比较。因为B与A不匹配,所以搜索词后移一位。
2.
B与A不匹配,搜索词向后移一位。直到有一位搜索词相同。
3.
可以看到前6个数都是相同的,但是最后一个数D与空格不相同。根据KMP算法,搜索词向后移动一位。但是这就是KMP算法效率低的地方,之前的6个数我们已经比较过了,已经不可能匹配了,但是KMP算法还是重复的匹配。在后面讲的Boyer-Moore算法会有优化。
4.
其实KMP在这里是有优化的,KMP算法的想法是,设法利用这个已知信息,不要把”搜索位置”移回已经比较过的位置,继续把它向后移,这样就提高了效率。
利用《部分匹配表》(Partial Match Table)可以根据公式:
移动位数 = 已匹配的字符数 – 对应的部分匹配值;
算出向后移动的位数。
5. 部分匹配表实例:
“部分匹配”的实质是,有时候,字符串头部和尾部会有重复。比如,”ABCDAB”之中有两个”AB”,那么它的”部分匹配值”就是2(”AB”的长度)。搜索词移动的时候,第一个”AB”向后移动4位(字符串长度-部分匹配值),就可以来到第二个”AB”的位置。
Boyer-Moore算法:
坏字符算法:
其实Boyer-Moore算法使用最多的是大部分软件里的“查找算法”。crtl+F4的功能。
注意:Boyer-Moore算法是从后向前匹配的。这是一个很聪明的想法,因为如果尾部字符不匹配,那么只要一次比较,就可以知道前7个字符(整体上)肯定不是要找的结果。
如上面的情况:
Boyer-Moore是怎么处理的呢?
我们看到,”C”与”D”不匹配。这时,”C”就被称为”坏字符”(bad character),即不匹配的字符。我们还发现,”C”包含在搜索词”ABCDABD”之中,这意味着可以把搜索词直接移到”C”的后一位。
我们看到,”D”与”空格不匹配。这时,空格就被称为”坏字符”(bad character),即不匹配的字符。我们还发现,空格不包含在搜索词”ABCDABD”之中,这意味着可以把搜索词直接移到空格的后一位。
而后面的“C”和“D”不相同,但是我们可以注意到坏字符“C”在搜索词“ABCDABD”中,根据规则我们将搜索词中的“C”移动到坏字符处:
这样,我们就找到了匹配的字符串了。。
我们可以总结Boyer-Moore的坏字符算法:
后移位数 = 坏字符的位置 – 搜索词中的上一次出现位置
即:坏字符“C”(上面的那一个C)出现在搜索词的第6位(从0开始),在搜索词中上一次出现的位置是2。所以6-2=4。
向后移动4位。
注意:如果”坏字符”不包含在搜索词之中,则上一次出现位置为 -1。
Boyer-Moore算法除了有”坏字符算法“还有
”好后缀算法“:
那么好后缀算法是什么样的情况呢?这里,我们得换个例子:
如果出现这种情况:
“MPLE”与”MPLE”匹配。我们把这种情况称为”好后缀”(good suffix),即所有尾部匹配的字符串。注意,”MPLE”、”PLE”、”LE”、”E”都是好后缀。
比较”I”与”A”不匹配,那么”I”就是坏字符。根据”坏字符规则”,此时搜索词应该后移 2 – (-1)= 3 位。但是在这里我们采用“好后缀算法”:
后移位数 = 好后缀的位置 – 搜索词中的上一次出现位置
此时,所有的”好后缀”(MPLE、PLE、LE、E)之中,只有”E”在”EXAMPLE”还出现在头部,所以后移 6 – 0 = 6位。
“坏字符规则”只能移3位,”好后缀规则”可以移6位。所以,Boyer-Moore算法的基本思想是,每次后移这两个规则之中的较大值。
继续从尾部开始比较,”P”与”E”不匹配,因此”P”是”坏字符”。根据”坏字符规则”,后移 6 – 4 = 2位。
匹配完成。。。