KMP算法中next函数值及其修正值算法的分析
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
KMP算法中next函数值及其修正值算法的分析
刘金魁;康超
【摘要】Data Structure is an important course in computer department,which is fairly theoretical and practical. The operation
of“string”has strong significance in theory and application. The pattern-matching KMP algorithm, the“next”function value and understanding of its modified value is the most important in this chapter,because its certain abstractness has caused some problems to readers. This article,aiming at the part,proposes some new under-standing ideas and the solution method.%《数据结构》课程是计算机专业的重要课程,有较强的理论性和专业实用性。
其中“串”的操作在理论和应用上都有很重要的意义;模式匹配的KMP算法以及next函数值及其修正值的理解是这一章的重中之重,因其一定的抽象性对阅读者造成了一定的困难。
文章针对这部分内容提出了一些新的思路和求解方法。
【期刊名称】《漯河职业技术学院学报》
【年(卷),期】2014(000)005
【总页数】2页(P44-45)
【关键词】串;KMP;next函数;nextval函数
【作者】刘金魁;康超
【作者单位】河南工业和信息化职业学院,河南焦作454000;河南工业和信息化职业学院,河南焦作454000
【正文语种】中文
【中图分类】TP301.6
在数据结构“串”的操作中,除了一些基本操作之外,最难的要数子串位置的定位函数index和在index上改进的KMP算法了。
KMP算法是这部分的难点之一,
同时又是一个比较精华的内容,而其中精华之精华又在于getnext函数,即求next[]值的方法。
在next[]的基础上,还可以再次进行改进,产生了一个
nextval[],即修正以后的next值。
数据结构的相关教材上给出了next值的定义:这对于一般读者不太好理解,我认真研究了一下next[]和nextval[],发现了其中
的简易规律,希望能对这部分的理解起到帮助作用。
KMP算法是一个改进的算法,为什么改进?改进了什么?要想回答这两个问题,
就需要拿原来的模式匹配算法与之相互比较,这样就会有更深刻的理解了。
我们习惯上用S表示主串,T表示模式串。
下面给出一个未经改进的模式匹配算法:
int Index(SString S,SString T,int pos)
{ i=pos;j=1;
while(i<=S[0] && j<=T[0])
{ if(S[i]==T[j]){++i;++j;}
else{i=i-j+2;j=1;}
}
if(j>T[0])return i-T[0];
else return 0;
}
如果能够匹配,也就是第一个if语句的条件能够满足,程序就“按部就班”执行。
若不匹配的话呢?也就是第一个if语句的条件不能满足,那就执行它的else子句,
从而给出重新开始匹配的位置,这我们称之为“回溯”。
为什么要“回溯”?这是因为T串本身前后有“部分匹配”的性质,否则就没有回溯的必要。
如果不用回溯,那T串下一个位置从哪里开始呢?这就是可以改进的地方,我们从T串本身
出发,找准T串自身前后“部分匹配”的位置,这样就可以改进算法。
看下面的例子:S:aaaaabababcaaa,T:ababc。
如果T的第五个字符“c”失配,那就可以往前移到字符串“aba”最后一个“a”的位置:
...ababa...
ababc
->ababc
此时i不用回溯,j跳到前2个位置,继续下面的匹配过程,这就是KMP算法的
本质思想。
当T[j]失配后,j应该回溯——也就是向前跳多少,就是其next的值,它是由T串自身来决定的,与S串没有关系。
但是我们希望利用已经得到的“部
分匹配”的结果将模式串向右“滑动”尽可能“远”的一段距离后,继续进行比较。
到此,我们就明白了KMP算法关键的问题是求next值,但是怎么求呢?方法就
是将T串与其本身做一次匹配,算法如下:
void get_next(SString T,int next[])
{i=1;j=0;next[1]=0;
while(i<=T[0])
{if(j==0 || T[i]==T[j]){++i;++j;next[i]=j;}
else j=next[j];
}
}
注意到上述程序第四行,该语句描述的就是next值的记录条件。
首先判断T[i]与
T[j]是否相等,来决定next[i]的值是否被新值所覆盖。
通过这样的循环比较,从而
确定next值的最终结果。
思路清晰,语句简洁。
在有些时候我们需要很快地求出next[]和nextval[]的值,在理解标准算法的基础
上我们可以“看”出某一模式串的next[]和nextval[]的值。
下面我们通过例子来
进行说明,首先看看next[]值的求解方法。
如表1所示。
关于next[]的求解方法很多书上有详细描述,但看起来似乎都不太好理解。
这里我们给出一种“通俗”的方法:模式串前两位的next值固定为0、1,从第三位开始就看它前面的任一字符串是否能和第一个字符开始的任一字符串相等,不等的话next值就为1;如果有相等的,就看相等字符串的最大长度,设其为x,那其
next值就是x+1。
以上面的模式串为例,第二个b前面有a,aa两个字符串,第一个字符开始有a,ab两个字符串,其中a是最大的相等字符串,长度为1,所以这个b的next值
就是1+1,为2。
再比如上述串的c,它前面有b,ab,aab三个字符串,第一个字符开始有a,ab,aba三个字符串,其中ab是最大相等字符串,长度为2,所以这个c的next值就是2+1,即为3。
这是next值的求法,但有时会产生多余的比较,我们就有了改进的方法,求nextval[],求nextval[]值方法有两种:直接观察法;推理法——根据next[]值进行推理。
两种方法效果相同,但显然前者更快速高效,下面我们主要分析第一种方法。
我们使用前面例子的模式串“abaabcac”来说明第一种方法。
字符串的第一个字符a的nextval值肯定为0。
直接对主串进行比较,如果比到第二位时发生了不匹配,则说明主串的第二位不为b,但它还可以为a,所以对主串第二位再进行一次比较。
此时偏移了1位,其nextval的值就是1。
以此类推,该串的nextval[]值分别为:01021302。
具体如表2所示。
Nextval[]值的第二种求法是根据next值进行推理计算的,很多书上都有讨论,这里不再赘述。
到此就完全弄清楚了KMP算法和next[]及nextval[]值的求法。
有的时候可能觉得KMP无法理解,其实不然,它只不过是对原有的模式匹配算法进行了改进。
在看KMP的时候,应仔细地比较改进前与改进后的差异,并搞清楚next[]和nextval[]值具体是怎么求的,这很关键。
在熟悉了这部分的内容以后,就会对算法思想有一个新的认识。
【相关文献】
[1] 严慰敏,吴伟民.数据结构(c语言版)[J].北京:清华大学出版社,2005.。