3:59 PM RK是好东西啊 |
Rabin-Karp算法在字符串匹配中其实也不算是很常用,但它的实用性还是不错的,除非你的运气特别差,最坏情况下可能会需要O((n-m)*m)的运行时间(关于n,m的意义请看上篇)。平均情况下,还是比较好的。 朴素的字符串匹配算法为什么慢? 因为它太健忘了,前一次匹配的信息其实可以有部分可以应用到后一次匹配中的,而朴素的字符串匹配算法只是简单的把这个信息扔掉,从头再来,因此,浪费了时间。好好的利用这些信息,自然可以提高运行速度。 这个算法不是那么容易说清楚,我举一个例子说下(看算法导论看到的例子)。 我们用E来表示字母表的字母个数,这个例子字母表如下:{0,1,2,3,4,5,6,7,8,9},那么E就是10,如果采用小写英文字母来做字母表,那么E就是26,类此。 由于完成两个字符串的比较需要对其中包含的字符进行检验,所需的时间较长,而数值比较则一次就可以完成,那么我们首先把模式(匹配的字串)转化成数值(转化成数值的好处不仅仅在此)。在这个例子里我们可以把字符0~9映射到数字0~9。比如,”423″,我们可以转化成3+E*(2+E*4)),这样一个数值,如果这个值太大了,我们可以选一个较大的质数对其取模,模后的值作为串的值。 这边处理好了,那么接下来转换被匹配的字符串,取前m个字符,如上述操作对其取值,然后对该值进行比较即可。 若不匹配,则继续向下寻找,这时候该如何做呢?比如模式是”423″,而父串是”324232″;第一步比较423跟324的值,不相等,下一步应该比较423跟242了,那么我们这步如何利用前一步的信息呢?首先我们把324前去300,然后在乘以E(这里是10),在加上2不就成了242了么?用个式子表示就是新的值a(i+1)=(E(a(i)-S[i])*h-S[S+M])) MOD p,p是我们选取的大质数,S[i]表示父串的第i个字符,而a(i)表示当前值,本例中就是324,h表示当前值最高位的权值,比如,324,则h=100,就是3这个位的权值,形式化的表示就是h=(E^m-1)MOD p。当然拉,由于采用了取模操作,当两者相等时,未必是真正的相等,我们需要进行细致的检查(进行一次朴素的字符串匹配操作)。若不相等,则直接可以排除掉。继续下一步。 伪代码,参加算法导论: n = len(T); m = len(p); h = d^(m-1)mod q; //表示进位 p = 0; t0 = 0; for i 1 to m p = (d*p+P[I]) mod q; t0 = (d*t0+T[I])mod q; for i 0 to n-m //从串S里面开始逐个搜索 if p==ti else ts+1 = d(ts-T[S+1]h) + T[S+M+1]mod q 问题描述: Rabin-Karp的预处理时间是O(m),匹配时间O( ( n - m + 1 ) m )既然与朴素算法的匹配时间一样,而且还多了一些预处理时间,那为什么我们还要学习这个算法呢?虽然Rain-Karp在最坏的情况下与朴素匹配一样,但是实际应用中往往比朴素算法快很多。而且该算法的期望匹配时间是O(n)【参照《算法导论》】,但是Rabin-Karp算法需要进行数值运算,速度必然不会比KMP算法快,那我们有了KMP算法以后为什么还要学习Rabin-Karp算法呢?个人认为学习的是一种思想,一种解题的思路,当我们见识的越多,眼界也就也开阔,面对实际问题的时候,就能找到更加合适的算法。比如二维模式匹配,Rabin-Karp就是一种好的选择。 而且Rabin-Karp算法非常有趣,将字符当作数字来处理,基本思路:如果Tm是一个长度为 |P| 的T的子串,且转换为数值后模上一个数(一般为素数)与模式字符串P转换成数值后模上同一个数的值相同,则Tm可能是一个合法的匹配。 (转载自http://blog.csdn.net/guyulongcs/article/details/7587633) |
|
Total comments: 0 | |