next数组求法
计算模式串t的next数组和nextval数组的值

计算模式串t的next数组和nextval数组的值在字符串匹配问题中,常常会用到模式串的next数组和nextval数组,这两个数组用于加速字符串的匹配过程。
1. next数组的计算:next[i]的值表示模式串t中,以第i个字符结尾的前缀字符串与后缀字符串的最长公共部分的长度。
具体计算方法如下:(1)首先求出模式串t的长度,假设为m;(2)初始化next数组的第一个元素next[0]为-1;(3)遍历模式串t的每个字符,假设当前遍历的字符是t[i]:- 初始化j = next[i - 1],j表示最大的相同前后缀的长度;- 如果t[j] == t[i],说明下一个最长的相同前后缀长度可以加1,即next[i] = j + 1;-如果t[j]!=t[i],则需要不断向前回溯,直到找到一个长度更小的相同前后缀,或者回溯到开始位置;-重复上述过程,直到遍历完整个模式串。
2. nextval数组的计算:相对于next数组来说,nextval数组的计算过程更为复杂,但是在一些情况下,它的效率更高。
具体计算方法如下:(1)首先求出模式串t的长度,假设为m;(2)初始化nextval数组的第一个元素nextval[0]为-1;(3)遍历模式串t的每个字符,假设当前遍历的字符是t[i]:- 初始化j = nextval[i - 1],j表示最大的相同前后缀的长度;- 如果t[j] == t[i],说明下一个最长的相同前后缀长度可以加1,即nextval[i] = j + 1;-如果t[j]!=t[i],则需要继续向前回溯,寻找到一个长度更小的相同前后缀;-如果t[j]!=t[i],则需要继续向前回溯,寻找到一个长度更小的相同前后缀;-如果j=-1,说明已经回溯到模式串的开始位置;-如果t[j]==t[i],说明找到了一个长度更小的相同前后缀;- 根据上述步骤的结果,得到nextval[i]的值。
需要注意的是,计算next数组和nextval数组的过程都是从模式串的第二个字符开始的,所以需要先初始化数组的第一个元素为-1下面以一个例子来具体说明如何计算next数组和nextval数组:假设模式串t为"ABCDABD",则模式串的长度为7首先计算next数组:- t[0]前面没有字符,所以next[0] = -1;- 遍历到t[1] = 'B',此时j = next[0] = -1;- t[j] = t[-1],跳过此步骤,直接执行next[1] = 0;- 遍历到t[2] = 'C',此时j = next[1] = 0;-t[j]!=t[2],需要继续向前回溯,因为j=0;- t[j] = t[-1],跳过此步骤,直接执行next[2] = 0;- 遍历到t[3] = 'D',此时j = next[2] = 0;-t[j]!=t[3],需要继续向前回溯,因为j=0;- t[j] = t[-1],跳过此步骤,直接执行next[3] = 0;- 遍历到t[4] = 'A',此时j = next[3] = 0;-t[j]!=t[4],需要继续向前回溯,因为j=0;- t[j] = t[-1],跳过此步骤,直接执行next[4] = 0;- 遍历到t[5] = 'B',此时j = next[4] = 0;-t[j]!=t[5],需要继续向前回溯,因为j=0;- t[j] = t[-1],跳过此步骤,直接执行next[5] = 0;- 遍历到t[6] = 'D',此时j = next[5] = 0;-t[j]!=t[6],需要继续向前回溯,因为j=0;- t[j] = t[-1],跳过此步骤,直接执行next[6] = 0;所以模式串t的next数组为:[-1, 0, 0, 0, 0, 0, 0]。
KMP算法Next数组详解

KMP算法Next数组详解题⾯题⽬描述如题,给出两个字符串s1和s2,其中s2为s1的⼦串,求出s2在s1中所有出现的位置。
为了减少骗分的情况,接下来还要输出⼦串的前缀数组next。
如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习⼀下就知道了。
输⼊输出格式输⼊格式:第⼀⾏为⼀个字符串,即为s1(仅包含⼤写字母)第⼆⾏为⼀个字符串,即为s2(仅包含⼤写字母)输出格式:若⼲⾏,每⾏包含⼀个整数,表⽰s2在s1中出现的位置接下来1⾏,包括length(s2)个整数,表⽰前缀数组next[i]的值。
输⼊样例:ABABABCABA输出样例:130 0 1说明时空限制:1000ms,128M数据规模:设s1长度为N,s2长度为M对于30%的数据:N<=15,M<=5对于70%的数据:N<=10000,M<=100对于100%的数据:N<=1000000,M<=1000题解这是⼀道KMP裸题(模板题。
)我就是拿着它学习⼀下KMP算法其实原来我学过KMP算法但是⼀直没有弄懂next(跳转)数组是如何求出来的。
最近花了⼀个下午⾃⼰研究了⼀下KMP算法现在终于觉得KMP很简单了~现在直接说next数组把⾄于有什么作⽤,next数组是⼲什么的,请⾃⾏百度,有很多dalao总结的⾮常到位,看⼀看就会明⽩。
好,来说next数组并不⽤在意这⼀坨⿊的是什么东西,我们就假设他是我们要求next数组的字符串。
next数组求的东西就是从起始位置到当前位置最长的相等的前缀和后缀的长度。
(举个例⼦China的前缀有:C、Ch、Chi、Chin、China ;后缀有a、na、ina、hina、China)我们继续,如上图红⾊的是当前位置(设为j)前,所匹配上的最长前缀和后缀,蓝⾊的是当前要匹配的位置。
那么,我们就拿当前位置和原来匹配到的最长前缀的后⼀位相⽐较如果两个位置相同,显然,可以和前⾯的红⾊连在⼀起,此时就有next[j]=next[j-1]+1如果两个位置不相同,根据next数组的性质,显然的,你的当前的相等的前缀和后缀只能够继续向前找,也就是说,你当前的next数组⼀定会减⼩。
next和nextval快速计算方法

题目:next和nextval的快速计算方法一、引言在计算机科学领域,next和nextval是两个常用的术语,它们通常用于描述序列中的下一个值。
在本文中,我们将介绍next和nextval的快速计算方法,并探讨其在实际应用中的重要性。
二、next和nextval的定义1. next:表示序列中的下一个值。
在数据库中,next通常用于自增列或者序列生成器中,用于产生下一个可用的值。
2. nextval:与next类似,也表示序列中的下一个值。
在某些数据库中,nextval用于获取序列的下一个值,并在插入新记录时使用。
三、传统计算方法的缺陷传统上,计算next和nextval的方法通常涉及到数据库的额外交互操作,特别是在高并发的情况下,这种方式往往效率较低,会带来一定的性能开销。
寻找快速计算方法成为了一个迫切的需求。
四、基于缓存的快速计算方法一种常见的快速计算方法是基于缓存的方式。
其基本思想是预先计算一定范围内的next或nextval,并将这些值缓存在内存中。
这样一来,当需要获取下一个值时,就可以直接从缓存中获取,避免了频繁的数据库交互操作。
具体实现时,可以通过定时任务或者事件触发来维护缓存的有效性,以确保缓存中的值始终是最新的。
为了保证并发安全,需要采取适当的锁机制来防止多个线程同时访问相同的缓存值。
五、基于预生成的快速计算方法除了基于缓存的方式外,另一种快速计算方法是基于预生成的方式。
其核心思想是在系统空闲时预先生成一定范围内的next或nextval,并将这些预生成的值存储在数据库中。
当需要获取下一个值时,就可以直接从预生成的值中获取,无需进行复杂的计算和交互操作。
需要注意的是,预生成的方式会占用一定的存储空间,并且需要设计合理的策略来管理预生成的值,以确保其始终能够满足系统的需求。
六、快速计算方法的实际应用快速计算方法在实际应用中具有重要的意义。
它可以显著提升系统的性能和吞吐量,特别是在高并发场景下。
next数组求法

int get_nextval(SString T,int &nextval[ ]){//求模式串T的next函数修正值并存入数组nextval。
i=1; nextval[1]=0; j=0;while(i<T[0]){if(j==0||T[i]==T[j]){++i;++j;if (T[i]!=T[j]) nextval[i]=j;else nextval[i]=nextval[j];}else j=nextval[j];}}//get_nextval根据这段程序来求nextval的值是可以方便计算出来,但如果是应付考研试题或者期末考试就有点麻烦了。
而如果记住我推荐的方法,那么任何时候都可以很方便地求解nextval 了。
首先看看next数组值的求解方法。
next数组的求解方法是:第一位的next值为0,第二位的next值为1,后面求解每一位的next值时,根据前一位进行比较。
首先将前一位与其next值对应的内容进行比较,如果相等,则该位的next值就是前一位的next值加上1;如果不等,向前继续寻找next值对应的内容来与前一位进行比较,直到找到某个位上内容的next值对应的内容与前一位相等为止,则这个位对应的值加上1即为需求的next值;如果找到第一位都没有找到与前一位相等的内容,那么需求的位上的next值即为1。
看起来很令人费解,利用上面的例子具体运算一遍。
1.前两位必定为0和1。
2.计算第三位的时候,看第二位b的next值,为1,则把b和1对应的a进行比较,不同,则第三位a的next的值为1,因为一直比到最前一位,都没有发生比较相同的现象。
3.计算第四位的时候,看第三位a的next值,为1,则把a和1对应的a进行比较,相同,则第四位a的next的值为第三位a的next值加上1。
为2。
因为是在第三位实现了其next值对应的值与第三位的值相同。
4.计算第五位的时候,看第四位a的next值,为2,则把a和2对应的b进行比较,不同,则再将b对应的next值1对应的a与第四位的a进行比较,相同,则第五位的next值为第二位b的next值加上1,为2。
计算模式串t的next数组和nextval数组的值

计算模式串t的next数组和nextval数组的值next数组和nextval数组是用于字符串匹配算法中的KMP算法中的两个重要辅助数组。
KMP算法是一种高效的字符串模式匹配算法,它的主要思想是在匹配过程中,通过已经匹配的字串信息来避免不必要的回溯,从而提高匹配的效率。
next数组和nextval数组正是为了实现这个目的而设计的。
1. next数组的计算next数组是指模式串t中,每个字符对应的最长前缀子串和最长后缀子串的公共部分的长度。
定义next数组为next[i],表示模式串t中以第i个字符结束的子串的最长公共前缀子串和最长公共后缀子串的长度。
具体计算步骤如下:- 初始化next[0] = -1,next[1] = 0;-i=2,j=0;- 当i < t.length时,执行以下循环:- 如果t.charAt(i-1) == t.charAt(j),则next[i] = j + 1,i++,j++;- 如果t.charAt(i-1) != t.charAt(j):- 如果j == 0,则next[i] = 0,i++;- 如果j != 0,则j = next[j],继续比较t.charAt(i-1)和t.charAt(j)。
最终得到的next数组即为所求。
2. nextval数组的计算nextval数组是在next数组的基础上进行改进得到的,主要用于在匹配失败时的跳转操作。
定义nextval数组为nextval[i],表示当t.charAt(i)与主串中的字符不匹配时,需要从模式串t中的哪个位置开始继续匹配。
具体计算步骤如下:- 初始化nextval[0] = -1,nextval[1] = 0;-i=2,j=0;- 当i < t.length时,执行以下循环:- 如果t.charAt(i-1) == t.charAt(j),则nextval[i] =nextval[j];- 如果t.charAt(i-1) != t.charAt(j):- 如果next[j] == 0,则nextval[i] = 0;- 如果next[j] != 0,则j = next[j],继续比较t.charAt(i-1)和t.charAt(j)。
javascript的next用法

javascript的next用法JavaScript的next是一个迭代器方法,它在迭代器的下一个非空值中返回一个对象。
它是ES6 (ECMAScript 2015)引入的新特性,用于简化JavaScript的迭代操作。
next方法有以下两个主要用途:1. 检查迭代器中是否还有值在使用迭代器遍历集合中的所有值时,可以使用next方法检查迭代器是否还有剩余的值。
如果next方法返回的value为undefined,则表示迭代器中没有其他值了。
例如,以下代码使用next方法遍历数组中的所有元素:```const array = ['apple', 'banana', 'orange'];const iterator = array[Symbol.iterator]();let result = iterator.next();while (!result.done) {console.log(result.value);result = iterator.next();}```该代码会打印出以下内容:```applebananaorange```在代码中,我们首先获取array的迭代器,并使用next方法获取第一个非空值。
然后我们使用while循环来检查是否还有其他可用的元素。
如果result.done为false,我们就可以访问迭代器返回的值result.value,本例中分别为‘apple’,‘banana’和‘orange’。
如果在循环中返回的result.done是true,则说明迭代器中没有其他的值。
2. 返回迭代器中的下一个非空值除了检查迭代器是否还有值,next方法还可以返回迭代器中的下一个非空值。
在返回该值之前,它还会使迭代器向前移动。
在该代码中,我们首先获取array的迭代器,并使用两个连续的next方法获取数组中的前两个非空元素。
KMP算法以及优化(代码分析以及求解next数组和nextval数组)

KMP算法以及优化(代码分析以及求解next数组和nextval数组)KMP算法以及优化(代码分析以及求解next数组和nextval数组)来了,数据结构及算法的内容来了,这才是我们的专攻,前⾯写的都是开胃⼩菜,本篇⽂章,侧重考研408⽅向,所以保证了你只要看懂了,题⼀定会做,难道这样思想还会不会么?如果只想看next数组以及nextval数组的求解可以直接跳到相应部分,思想总结的很⼲~~⽹上的next数组版本解惑先总结⼀下,⼀般KMP算法的next数组结果有两个版本,我们需要知道为什么会存在这种问题,其实就是前缀和后缀没有匹配的时候next数组为0还是为1,两个版本当然都是对的了,如果next数组为0是的版本,那么对于前缀和后缀的最⼤匹配长度只需要值+1就跟next数组是1的版本⼀样了,其实是因为他们的源代码不⼀样,或者对于模式串的第⼀个下标理解为0或者1,总之这个问题不⽤纠结,懂原理就⾏~~那么此处,我们假定前缀和后缀的最⼤匹配长度为0时,next数组值为1的版本,考研⼀般都是⽤这个版本(如果为0版本,所有的内容-1即可,如你算出next[5]=6,那么-1版本的next[5]就为5,反之亦然)~~其实上⾯的话总结就是⼀句话next[1]=0,j(模式串)数组的第⼀位下标为1,同时,前缀和后缀的最⼤匹配长度+1即为next数组的值,j所代表的的是序号的意思408反⼈类,⼀般数组第⼀位下标为1,关于书本上前⾯链表的学习⼤家就应该有⽬共睹了,书本上好多数组的第⼀位下标为了⽅便我们理解下标为1,想法这样我们更不好理解了,很反⼈类,所以这⾥给出next[1]=0,前缀和后缀的最⼤匹配长度+1的版本讲解前⾔以及问题引出我们先要知道,KMP算法是⽤于字符串匹配的~~例如:⼀个主串"abababcdef"我们想要知道在其中是否包括⼀个模式串"ababc"初代的解决⽅法是,朴素模式匹配算法,也就是我们主串和模式串对⽐,不同主串就往前移⼀位,从下⼀位开始再和模式串对⽐,每次只移动⼀位,这样会很慢,所以就有三位⼤神⼀起搞了个算法,也就是我们现在所称的KMP算法~~代码以及理解源码这⾥给出~~int Index_KMP(SString S,SString T,intt next[]){int i = 1,j = 1;//数组第⼀位下标为1while (i <= S.length && j <= T.length){if (j == 0 || S.ch[i] == T.ch[j]){//数组第⼀位下标为1,0的意思为数组第⼀位的前⾯,此时++1,则指向数组的第⼀位元素++i;++j; //继续⽐较后继字符}elsej = next[j]; //模式串向右移动到第⼏个下标,序号(第⼀位从1开始)}if (j > T.length)return i - T.length; //匹配成功elsereturn 0;}接下来就可以跟我来理解这个代码~~还不会做动图,这⾥就⼿画了~~以上是⼀般情况,那么如何理解j=next[1]=0的时候呢?是的,这就是代码的思路,那么这时我们就知道,核⼼就是要求next数组各个的值,对吧,⼀般也就是考我们next数组的值为多少~~next数组的求解这⾥先需要给出概念,串的前缀以及串的后缀~~串的前缀:包含第⼀个字符,且不包含最后⼀个字符的⼦串串的后缀:包含最后⼀个字符,且不包含第⼀个字符的⼦串当第j个字符匹配失败,由前1~j-1个字符组成的串记为S,则:next[j]=S的最长相等前后缀长度+1与此同时,next[1]=0如,模式串"ababaa"序号J123456模式串a b a b a anext[j]0当第六个字符串匹配失败,那么我们需要在前5个字符组成的串S"ababa"中找最长相等的前后缀长度为多少再+1~~如串S的前缀可以为:"a","ab","aba","abab",前缀只不包括最后⼀位都可串S的后缀可以为:"a","ba","aba","baba",后缀只不包括第⼀位都可所以这⾥最⼤匹配串就是"aba"长度为3,那么我们+1,取4序号J123456模式串a b a b a anext[j]04再⽐如,当第⼆个字符串匹配失败,由前1个字符组成的串S"a"中,我们知道前缀应当没有,后缀应当没有,所以最⼤匹配串应该为0,那么+1就是取1~~其实这⾥我们就能知道⼀个规律了,next[1]⼀定为0(源码所造成),next[2]⼀定为1(必定没有最⼤匹配串造成)~~序号J123456模式串a b a b a anext[j]014再再⽐如,第三个字符串匹配失败,由前两个字符组成的串S"ab"中找最长相等的前后缀长度,之后再+1~~前缀:"a"后缀:"b"所以所以这⾥最⼤匹配串也是没有的长度为0,那么我们+1,取1序号J123456模式串a b a b a anext[j]0114接下来你可以⾃⼰练练4和5的情况~~next[j]011234是不是很简单呢?⾄此,next数组的求法以及kmp代码的理解就ok了~~那么接下来,在了解以上之后,我们想⼀想KMP算法存在的问题~~KMP算法存在的问题如下主串:"abcababaa"模式串:"ababaa"例如这个问题我们很容易能求出next数组序号J123456模式串a b a b a anext[j]011234此时我们是第三个字符串匹配失败,所以我们的next[3]=1,也就是下次就是第⼀个字符"a"和主串中第三个字符"c"对⽐,可是我们刚开始的时候就已经知道模式串的第三个字符"a"和"c"不匹配,那么这⾥不就多了⼀步⽆意义的匹配了么?所以我们就会有kmp算法的⼀个优化了~~KMP算法的优化我们知道,模式串第三个字符"a"不和主串第三个字符"c"不匹配,next数组需要我们的next[3]=1,也就是下次就是第⼀个字符"a"和主串中第三个字符"c"对⽐,之后就是模式串第⼀个字符"a"不和"c"匹配,就是需要变为next[1]=0,那么我们要省去步骤,不就可以直接让next[3]=0么?序号J12345模式串a b a b anext[j]01123nextval[j]00那么怎么省去多余的步骤呢?这就是nextval数组的求法~~nextval的求法以及代码理解先贴出代码for (int j = 2;j <= T.length;j++){if (T.ch[next[j]] == T.ch[j])nextval[j] = nextval[next[j]];elsenextval[j] = next[j];}如序号J123456模式串a b a b a anext[j]011234nextval[j]0⾸先,第⼀次for循环,j=2,当前序号b的next[2]为1,即第⼀个序号所指向的字符a,a!=当前序号b,所以nextval[2]保持不变等于next[2]=1序号J123456模式串a b a b a anext[j]011234nextval[j]01第⼆次for循环,j=3,当前序号a的next[3]为1,即第⼀个序号所指向的字符a,a=当前序号a,所以nextval[3]等于nextval[1]=0序号J123456模式串a b a b a anext[j]011234nextval[j]010第三次for循环,j=4,当前序号b的next[4]为2,即第⼆个序号所指向的字符b,b=当前序号b,所以nextval[4]等于nextval[2]=1序号J123456模式串a b a b a anext[j]011234nextval[j]0101就是这样,你可以练练5和6,这⾥直接给出~~序号J123456模式串a b a b a anext[j]011234nextval[j]010104⾄此nextval数组的求法你也应该会了,那么考研要是考了,那么是不是就等于送分给你呢?⼩练习那么你试着来求⼀下这个模式串的next和nextval数组吧~~next[j]nextval[j]⼩练习的答案序号j12345模式串a a a a b next[j]01234 nextval[j]00004。
kmp算法next函数详解

kmp算法next函数详解KMP算法在介绍KMP算法之前,先介绍⼀下BF算法。
⼀.BF算法BF算法是普通的模式匹配算法,BF算法的思想就是将⽬标串S的第⼀个字符与模式串P的第⼀个字符进⾏匹配,若相等,则继续⽐较S的第⼆个字符和P的第⼆个字符;若不相等,则⽐较S的第⼆个字符和P的第⼀个字符,依次⽐较下去,直到得出最后的匹配结果。
举例说明:S: ababcababaP: ababaBF算法匹配的步骤如下i=0 i=1 i=2 i=3 i=4第⼀趟:a babcababa 第⼆趟:a b abcababa 第三趟:ab a bcababa 第四趟:aba b cababa 第五趟:abab c ababaa baba ab aba ab a ba aba b a abab aj=0 j=1 j=2 j=3 j=4(i和j回溯)i=1 i=2 i=3 i=4 i=3第六趟:a b abcababa 第七趟:ab a bcababa 第⼋趟:aba b cababa 第九趟:abab c ababa 第⼗趟:aba b cababaa baba a baba ab aba ab a ba a babaj=0 j=0 j=1 j=2(i和j回溯) j=0i=4 i=5 i=6 i=7 i=8第⼗⼀趟:abab c ababa 第⼗⼆趟:ababc a baba 第⼗三趟:ababca b aba 第⼗四趟:ababcab a ba 第⼗五趟:ababcaba b aa baba a baba ab aba ab a ba aba b aj=0 j=0 j=1 j=2 j=3i=9第⼗六趟:ababcabab aabab aj=4(匹配成功)代码实现:int BFMatch(char*s,char*p){int i,j;i=0;while(i<strlen(s)){j=0;while(s[i]==p[j]&&j<strlen(p)){i++;j++;}if(j==strlen(p))return i-strlen(p);i=i-j+1; //指针i回溯}return-1;}其实在上⾯的匹配过程中,有很多⽐较是多余的。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
int get_nextval(SString T,int &nextval[ ]){
//求模式串T的next函数修正值并存入数组nextval。
i=1; nextval[1]=0; j=0;
while(i<T[0]){
if(j==0||T[i]==T[j]){
++i;++j;
if (T[i]!=T[j]) nextval[i]=j;
else nextval[i]=nextval[j];
}
else j=nextval[j];
}
}//get_nextval
根据这段程序来求nextval的值是可以方便计算出来,但如果是应付考研试题或者期末考试就有点麻烦了。
而如果记住我推荐的方法,那么任何时候都可以很方便地求解nextval 了。
首先看看next数组值的求解方法。
例如:
模式串 a b a a b c a c
next值0 1 1 2 2 3 1 2
nextval值
next数组的求解方法是:第一位的next值为0,第二位的next值为1,后面求解每一位的next值时,根据前一位进行比较。
首先将前一位与其next值对应的内容进行比较,如果相等,则该位的next值就是前一位的next值加上1;如果不等,向前继续寻找next值对应的内容来与前一位进行比较,直到找到某个位上内容的next值对应的内容与前一位相等为止,则这个位对应的值加上1即为需求的next值;如果找到第一位都没有找到与前一位相等的内容,那么需求的位上的next值即为1。
看起来很令人费解,利用上面的例子具体运算一遍。
1.前两位必定为0和1。
2.计算第三位的时候,看第二位b的next值,为1,则把b和1对应的a进行比较,不同,则第三位a的next的值为1,因为一直比到最前一位,都没有发生比较相同的现象。
3.计算第四位的时候,看第三位a的next值,为1,则把a和1对应的a进行比较,相同,则第四位a的next的值为第三位a的next值加上1。
为2。
因为是在第三位实现了其next值对应的值与第三位的值相同。
4.计算第五位的时候,看第四位a的next值,为2,则把a和2对应的b进行比较,不同,则再将b对应的next值1对应的a与第四位的a进行比较,相同,则第五位的next值为第二位b的next值加上1,为2。
因为是在第二位实现了其next值对应的值与第四位的值相同。
5.计算第六位的时候,看第五位b的next值,为2,则把b和2对应的b进行比较,相同,则第六位c的next值为第五位b的next值加上1,为3,因为是在第五位实现了其next 值对应的值与第五位相同。
6.计算第七位的时候,看第六位c的next值,为3,则把c和3对应的a进行比较,不同,则再把第3位a的next值1对应的a与第六位c比较,仍然不同,则第七位的next值为1。
7.计算第八位的时候,看第七位a的next值,为1,则把a和1对应的a进行比较,相
同,则第八位c的next值为第七位a的next值加上1,为2,因为是在第七位和实现了其next值对应的值与第七位相同。
在计算nextval之前要先弄明白,nextval是为了弥补next函数在某些情况下的缺陷而产生的,例如主串为“aaabaaaab”、模式串为“aaaab”那么,比较的时候就会发生一些浪费的情况:比较到主串以及模式串的第四位时,发现其值并不相等,据我们观察,我们可以直接从主串的第五位开始与模式串进行比较,而事实上,却进行了几次多余的比较。
使用nextval 可以去除那些不必要的比较次数。
求nextval数组值有两种方法,一种是不依赖next数组值直接用观察法求得,一种方法是根据next数组值进行推理,两种方法均可使用,视更喜欢哪种方法而定。
我们使用例子“aaaab”来考查第一种方法。
1.试想,在进行模式匹配的过程中,将模式串“aaaab”与主串进行匹配的时候,如果第一位就没有吻合,即第一位就不是a,那么不用比较了,赶快挪到主串的下一位继续与模式串的第一位进行比较吧,这时,模式串并没有发生偏移,那么,模式串第一位a的nextval值为0。
2.如果在匹配过程中,到第二位才发生不匹配现象,那么主串的第一位必定是a,而第二位必定不为a,既然知道第二位一定不为a,那么主串的第一、二两位就没有再进行比较的必要,直接跳到第三位来与模式串的第一位进行比较吧,同样,模式串也没有发生偏移,第二位的nextval值仍然为0。
3.第三位、第四位类似2的过程,均为0。
4.如果在匹配过程中,直到第五位才发生不匹配现象,那么主串的第一位到第四位必定为a,并且第五位必定不为b,可是第五位仍然有可能等于a。
如果万一第五位为a,那么既然前面四位均为a,所以,只要第六位为b,第一个字符串就匹配成功了。
所以,现在的情况下,就是看第五位究竟是不是a了。
所以发生了下面的比较:
1 2 3 4 5 6
a a a a * *
a a a a b
a a a a b
前面的三个a都不需要进行比较,只要确定主串中不等于b的那个位是否为a,即可以进行如下的比较:如果为a,则继续比较主串后面一位是否为b;如果不为a,则此次比较结束,继续将模式串的第一位去与主串的下一位进行比较。
由此看来,在模式串的第五位上,进行的比较偏移了4位(不进行偏移,直接比较下一位为0),故第五位b的nextval值为4。
我们可以利用第一个例子“abaabcac”对这种方法进行验证。
a的nextval值为0,因为如果主串的第一位不是a,那么没有再比较下去的必要,直接比较主串的第二位是否为a。
如果比较到主串的第二位才发生错误,则主串第一位肯定为a,第二位肯定不为b,此时不能直接跳到第三位进行比较,因为第二位还可能是a,所以对主串的第二位再进行一次比较,偏移了1位,故模式串第二位的nextval值为1。
以此类推,nextval值分别为:01021302。
其中第六位的nextval之所以为3,是因为,如果主串比较到第六位才发生不匹配现象,那么主串的前五位必定为“abaab”且第六位必定不是“c”,但第六位如果为“a”的话,那么我们就可以从模式串的第四位继续比较下去。
所以,这次比较为:
1 2 3 4 5 6 7 8 9 10 11 12
a b a a b * * * * * * *
a b a a b c a c
而不是:
1 2 3 4 5 6 7 8 9 10 11 12
a b a a b * * * * * * *
a b a a b c a
因为前两位a和b已经确定了,所以不需要再进行比较了。
所以模式串第六位的nextval 值为这次比较的偏移量3。
再来看求nextval数组值的第二种方法。
模式串 a b a a b c a c
next值0 1 1 2 2 3 1 2
nextval值0 1 0 2 1 3 0 2
1.第一位的nextval值必定为0,第二位如果于第一位相同则为0,如果不同则为1。
2.第三位的next值为1,那么将第三位和第一位进行比较,均为a,相同,则,第三位的nextval值为0。
3.第四位的next值为2,那么将第四位和第二位进行比较,不同,则第四位的nextval 值为其next值,为2。
4.第五位的next值为2,那么将第五位和第二位进行比较,相同,第二位的next值为1,则继续将第二位与第一位进行比较,不同,则第五位的nextval值为第二位的next值,为1。
5.第六位的next值为3,那么将第六位和第三位进行比较,不同,则第六位的nextval 值为其next值,为3。
6.第七位的next值为1,那么将第七位和第一位进行比较,相同,则第七位的nextval 值为0。
7.第八位的next值为2,那么将第八位和第二位进行比较,不同,则第八位的nextval 值为其next值,为2。
在“aaaab”内进行验证。
模式串 a a a a b
next值0 1 2 3 4
nextval值0 0 0 0 4。