KMP算法

KMP算法是一种查询模式串在主串中第一次出现的位置的算法。比起朴素的BF算法来说,效率高上一点,如果模式串中出现的重复字符多的话,效率会更高。

BF算法的核心思想就是将主串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符;若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。

KMP算法的匹配方式和BF算法一致,只是KMP的核心在于减少无意义的回溯,即每一次模式串匹配失败都进行一次最大的跳跃。

KMP算法针对的是模式串,对主串不作处理,KMP算法其实就是实现了一个next()函数,函数返回模式串在每一个下标处出现失配时的回溯指针,即匹配时不回溯主串的当前位置指针,只回溯模式串的位置指针。

我们令模式串的位置指针为j。j的回溯情况有next()函数求出,由模式串的前缀和后缀相似程度决定,我们需要求出最长相等的前缀与后缀的长度,如模式串为(以数组下标表示位置):a b a b a a,那对于下标为2的字符a来说,他的最长相等前后缀长度为0,对于下标为4的a来说他的最长相等前后缀长度为2(a b),同理对于下标为5的a来说,最长相等前后缀长度为3(a b a)。

为什么要确定最长相等的前后缀,这就是KMP算法的具体实现,因为前缀与后缀相等,就不需要按照BF逐步比较,因为主串与模式串S(a b a b a a)如果在S[4]的地方失配,那就说明S[0]到S[3]和主串是一致的,而且我们发现S[0] == S[2],S[1] == S[3],我们就可以直接将匹配位置跳转到S[2],因为主串在对应S[2]与S[3]地方一定和S[0]与S[1]对应。

下面是next()的具体实现:

void get_next(String& str,int (&next)[255])
{
     int prefix,postfix;
     next[0] = -1;
     prefix = 0;                 
     postfix = 1;               
     while(postfix != str.length)
     {
         if(str.str[0] == str.str[1])
         {
             next[1] = -1;          
         }
         else
         {
             next[1] = 0;
         }
         if(prefix == -1 || str.str[prefix] == str.str[postfix])
         {
             prefix++;
             postfix++;
             if(str.str[prefix] != str.str[postfix])
             {
                 next[postfix] = prefix;
             }
             else
             {
                 next[postfix] = next[prefix];
             }
         }
         else
         {
             prefix = next[prefix];
         }
     }
}

想要理解KMP算法,要对理解对于模式串来说,前缀是固定的,后缀是浮动的,前缀的下标的意义是当前匹配的最长相等前后缀的长度,一旦发生前后缀失配,我们需要回溯的就是前缀,继续寻找当前匹配的最长相等前后缀长度,我们需要利用的就是前面求出的next数组,要理解next数组的含义:模式串在每一个下标处出现失配时的回溯指针。

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