KMP算法详解

      字符串查找子串是计算机程序设计经常会遇到的难题。举个例子来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"?

    完成这个任务有很多算法,KMP是最常用的算法之一,下面通过一个例子来详细描述一下这个算法:

1.


    首先将子串与搜索串的第一个字符进行比较,因为不匹配,所以将子串向后移动直到

2.


    当第一个字符相等时,再次比较第二个字符,直到

3.


    此时,要查找的子串并没有找到,且与查找串对应的字符不相等。这时候,最自然的办法是将查找串中的下一个字符,重新开始,如下所示:

4.


    虽然这样查找是可行的,但是效率是及其低下的,因为它需要将比较过的字符串再次进行比较。KMP算法的思想是,设法利用已经比较过的字符串信息,不要把搜索的位置移动到已经比较过的地方。KMP算法的核心是利用一张部分匹配的表,根据表的值,可以计算当匹配不成功的时候应该向后移动的位数。

5. 


    那么,如何计算这张表呢?首先应该了解两个概念,“前缀”和“后缀”,前缀指的是除了最后一个字符以外,一个字符串的全部头部的组合;后缀指的是除了第一个字符意外,一个字符串全部尾部的集合。而部分匹配表指的是前缀和后缀共有字符的最大长队。还是举这个例子:

  • "A"的前缀和后缀都为空集,共有元素的长度为0;
  • "AB"的前缀为[A],后缀为[B],共有元素的长度为0;
  • ABC"的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;
  • "ABCD"的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为0;
  • "ABCDA"的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为"A",长度为1;
  • "ABCDAB"的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为"AB",长度为2;
  • "ABCDABD"的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为0;
6. 


    已知空格与D不匹配时,前面六个字符"ABCDAB"是匹配的。查表可知,最后一个匹配字符B对应的"部分匹配值"为2,因此按照下面的公式算出向后移动的位数:

移动位数 = 已匹配的字符数 - 对应的部分匹配值

     因为 6 - 2 等于4,所以将搜索词向后移动4位。   

7. 


    因为空格与C不匹配,搜索词还要继续往后移。这时,已匹配的字符数为2("AB"),对应的"部分匹配值"为0。所以,移动位数 = 2 - 0,结果为 2,于是将搜索词向后移2位。

8. 

  

    因为空格与A不匹配,继续后移一位。

9.


    逐位比较,直到发现C与D不匹配。于是,移动位数 = 6 - 2,继续将搜索词向后移动4位。

10. 


    逐位比较,直到搜索词的最后一位,发现完全匹配,于是搜索完成。如果还要继续搜索(即找出全部匹配),移动位数 = 7 - 0,再将搜索词向后移动7位,这里就不再重复了。


你可能感兴趣的:(算法,KMP)