KMP算法

来源:互联网 发布:定时开关机软件 编辑:程序博客网 时间:2024/06/07 11:16

     关于KMP算法,看着书上的解释很费解,反而按他的原理自己解释的话感觉好很多。

     这里只讨论思想,并不涉及代码分析。

   

     KMP算法其实很简单,它的目的只是减少串与串比较的次数从而提高效率。而它的原理也仅仅是通过对子串中的重复字符进行记录,从而在与主串比较的时候省去不必要的比较。

     例如:  子串:abchhabcj

             主串:zxcazxcdabchhabcjzswq

 

    可以想象,1.如果第一个字符a不相等,那么将第一个字符a与主串中的下一个字符比较……;

              2.如果一直到第八个字符c,子串与主串都匹配,但是子串中第九个字符j却与主串不匹配,那么

                可以直接放弃第一个字符a与下一个字符的比较,直接将子串“滑动”到第六个字符的所在位

                置再与主串比较。舍弃了中间那段的比较步骤。

    总结以上说法就是说:子串中1~3和6~8的字符是重复的,当子串中的1~3的字符和6~8字符与主串匹配,如果可以确定子串中的4,5两个字符也与主串匹配(也就是说确定4,5两个字符对应的主串的字符与第一个字符串不相等)那么可以放弃子串中第一个字符与主串中这两个字符的比较,直接跳到第六个字符对应的位置比较。

 

    由以上想法可以推出:比较的时候可以不必须找与子串中第一字符重复的字符,可以找任意重复字符,只是比较的时候将主串与子串的下标同时减n(n为重复字符到第一个字符的距离);

        

   可以看出,KMP算法的重点不是在主串的比较,而是在于找子串中重复的字符,即书上说的next[j]函数。

 

   关于next[j]函数,其实也很简单,和函数名一样next[j]函数是利用数组储存信息,问题在于,它储存的是什么信息。KMP的思想在于寻找子串中重复字符,所以next[j]函数储存的自然是关于字符的信息。了解他的本质一切就好理解了。

 

   因为系统定义的数组只能存储一个类型数据,所以为方便使用不考虑自定义的结构体数组(没必要)。书上的next[j]函数用的是容易理解的储存重复字符下标的方法,相信大家调用next[j]函数的时候从next[j]中的值可以看出很多线索,但是却感觉解释不通。

   例如:

          t : 0 1 2 3 4 5 6 7 8 9

        子串:f e n a a a f e n b 

 

        为什么t[2]和t[8]比较要存在next[9]中哪?其实道理很简单,我们先明确KMP算法的目的是为了较少比较次数,那么如果t[8]与主串匹配,但是t[9]却与主串不匹配,那么下一次比较你是不是要直接比较t[3]是不是与t[9]对应的主串匹配?(建议在纸上画画,这是逻辑思想,与主串其实没有关系,就像你妈让你往银行卡里存200元,存钱前第一步要确定是不是这张卡,第二步就是存200元钱,但是你却只掏出100元,那么你掏出剩下的100元时还用返回第一步去检查是不是这个卡么?)也就是说next[j]中储存的下标!!其实不是相等字符的下标,而是不相等字符的下标!!记住这句话!你可以去比较,next[9]=3其实是说t[9]的前一个字符与t[3]的前一个字符相等,注意是前一个!和上面说的一样,这么做的原理是跳过了主串中与t[6]t[7]t[8]对应的字符与t[0]t[1]t[2]的比较,直接将t[3]与t[9]对应的字符比较,而默认前面的3个字符匹配(本来就匹配)。

 

       下面说下next[j]函数中的一些细节:

        1.-1,0是函数中特殊的数,它们的作用自然是标记,0就是空,表示的自然是没有的意思,也就是说没有重复,而-1自然表示失败,失败的因素有很多,可以是子串没有重复字符,也可以是主串没有与子串匹配的字符。至于其他的数可以理解为在第j+1个字符前重复的字符数,也可以理解为重复字符的后一个的下标。哪为什么规定next[0]=-1;因为t[0]的前一个字符是没有的,也就是说next[0]储存的下标一定是没用的,所以我 认为他是废物利用…,而规定其他的不重复的为0就可以自然理解为利用k=next[k];直接调到next[0]中。

        2.K值:子串中重复只是对于第一个字符讲,也就是说子串中的重复串只是将后面的字符串与以第一个字符为首的字符串比较,这就出现了多个与首字符重复的字符问题,这就会产生K的值,但是真正比较时候会发现k值并没那么高大,因为你会发现有用的只是k的最大值,也就是说k从0一直加上来的那个过程其实是没有利用价值的过渡产品。

       3.方法:熟读kmp算法以后会发现next[j]函数的代码和KMP算法的代码神似……不由感慨:到底是KMP发明者,真的是灵活使用…

原创粉丝点击