关于KMP算法当中的next函数

来源:互联网 发布:ubuntu永久挂载硬盘 编辑:程序博客网 时间:2024/06/06 18:18

转载来源:http://blog.csdn.net/phil2036/article/details/2068674



  首先先贴出KMP算法的框架代码,这段代码使用C语言当中的字符串数据结构,因此字符串当中第一个字符的下标为零。

int Index(const char * str1,const char * str2,int pos)
{
    
int * nextFunc = get_next(str2);
    
int strLen = strlen(str1);
    
int subLen = strlen(str2);
    
int i = pos,j = 0;
    
while (i < strLen && j < subLen)
 
{
        
if (j == -1 || str1[i] == str2[j])
    
{
            i
++;
            j
++;
        }

        
else
            j 
= nextFunc[j];
    }

    
if (j == subLen)
        
return i - subLen;
    
return -1;
}

        相比较那种最简单的算法而言这里的神奇之处在于一个next函数,由于这个next函数的存在导致我们在模式匹配过程当中某个字符出现失配的情况时不再需要回溯主串当中的指针i到开始匹配时的位置。所有的数据结构或者算法的书都告诉我们说,之所以不需要回溯这个i指针是因为在匹配过程当中产生了一些附加的信息,利用这些附加信息就可以得到这样的性能改进。

        首先我们必须搞清楚这个神奇的next函数的含义。next[j]=k 这样一个式子表示的含义是,当主串当中第i个元素与模式串当中第j个元素不匹配时我们应该保持i指针不动而将模式串当中的j指针移动到k这个位置,然后再比较主串的第i个元素与模式串的第k个元素是否匹配,匹配当然没话说照最传统的算法移动两个指针比较下一个元素或者得到完全匹配的结果,不匹配那么再做那个动作,也就是求next[k]=?,然后再比较。

        之所以存在这么一个next函数是因为,如果说主串与模式串在匹配过程当中主串的第i个元素与模式串的第j个元素不同,那么隐含的意义是主串的从第i-j+1个元素到第i-1个元素与模式串的第1个元素到第j-1个元素是相同的。那么如果说这样不能达到最后全部匹配的结果也就是上面讲的主串[i] != 模式串[j],那么我们应该从主串的i-j+1到i-1这个字串当中从后到前寻找一个最大子串与模式串的第1到j-1这个字串的从第一个到某个元素的最大子串完全匹配。而我们又知道主串中第i-j+1个元素到第i-1个元素的子串事实上就是模式串当中第1个元素到第j-1个元素所形成的子串。next函数所完成的工作就是这个寻找匹配的工作,他的返回值就是这个子串的最后一个元素的下一个位置。为什么是这个位置,前面讲的很清楚,就是说既然前面那一串匹配,那么接下来要比较的就是这个位置的元素。下面开始描述next函数的求法。

        从上面的描述我们可以知道next函数的值完全只与模式串相关而与主串是什么样子的没有任何关系,因此来说对于每个模式串都有一个唯一的next串值。求法是这样,如果说自变量为0也就是说第一个元素的next值固定为-1(-1的意思是说,主串的当前位置元素与模式串第一个元素的前一个元素匹配,隐含意义是讲主串指针必须往后移一位再与模式串的第一个元素比较);如果next[j] = k也就是说模式串的第1个元素到第k个元素与第j-k+1个元素到第j-1个元素相等相等(可以按照上面的方法推出到主串上哪几个元素),而且有模式串[j] == 模式串[k]那么可以得到next[j+1] = k+1(这里的原理显而易见);如果不等那么就求另外一个最大子串,方法就是j = next[k],然后再回到上面的比较。而其他的情况就视作next值为0(事实上只有求j=1时的next值才会出现,所以next值的前两个元素固定是0和1)。具体算法如下:

int * get_next(const char * str)
{
    
int strLen = strlen(str);
    
int * nextFunc = new int[strLen];
    
if (!nextFunc)
        
return 0;
    nextFunc[
0= -1;
    
int i = 0,j = nextFunc[i];
    
while (i < strLen)
{
        
if (j == -1 || str[i] == str[j])
    
{
            i
++;
            j
++;
            nextFunc[i] 
= next[i-1] + 1;
        }

        
else
            j 
= nextFunc[j];                    
    }
    
return nextFunc;
}

注:本文所有的串表示方法都是C语言的默认表示方法,也就是第一个元素的下标为0


原创粉丝点击