字符串匹配算法 -- Rabin-Karp 算法
参考资料
1 算法导论

Rabin-karp 算法简介

在实际应用中,Rabin-Karp 算法对字符串匹配问题能较好的运行。Rabin-Karp 算法需要对字符串和模式进行预处理,其预处理时间为 O ( m ) ,在最坏情况下的运行时间为 O ( ( n-m+1 ) m ) ,但基于某种假设(不知道是何种假设),它的平均情况下的运行时间还是比较好的。
为了便于说明,假设 
∑ = { 0,1,2.....9 },这样每个字符都是一个十进制数字。(对于更一般的情况,可以假设每个字符都是基数为 d 的表示法中的一个数字,d = | ∑ | 。)可以用一个长度为 k 的十进制数来表示由 k 个连续字符组成的字符串。因此,字符串31415 就对应于十进制数 31415 。

已知一个模式 P[ 1.. m ],设 p 表示该模式所对应的十进制数的值(如模式 P = "31415" ,数值p = 31415)。对于给定的文本 T [ 1.. n ],用 ts 来表示其长度为 m 的子字符串 T [ s+1.. s+m ] (s = 0,1,.. n-m)相对应的十进制数的值。ts = p 当且仅当 T [ s+1.. s+m ] = P[ 1.. m ] ,因此 s 是有效位移当且仅当 ts = p 。

预处理 -- p 和 t0

于是应用霍纳法则(Horner's Rule)在 O ( m ) 的时间内计算 p 的值:
         p = P[ m ] + 10( P[ m-1 ] + 10 ( P[ m-2 ] + .. + 10( P[ 2] + P[ 1 ]) ... ))
类似的,也可以在 O ( m ) 时间内根据 T[ 1.. m ] 计算出 t0 的值。
为了在 O ( n - m ) 的时间内计算出剩余的值 t1,t2,...,t ( n - m ),可以在常数时间内根据 ts 计算出 t ( s+1 )。因为
        t ( s + 1) = 10 ( ts - 10^(m-1) T [ s+1 ] ) + T [ s + m +1]             ( 1 )
事实上,就是去掉最高位,然后左移了一位,在加上 T [ s + m +1] ,就得到了 t ( s + 1) 。
预处理的时间为 O ( m )

字符串匹配

当进行完预处理之后,就可以执行字符串匹配了。我们只需要将 ti ( i = 0 , 1 ,  ...  n-m ) 与 p 进行比较,相等则为合法匹配,否则为非法匹配。整个匹配过程的时间为 O ( n -m + 1 )

然而,上述问题对于模式 p 的长度较小时,比较方便。当 p 和 ts 的值很大时,p 的结果会太大,以至于不能很好的处理这类问题 。所以才有了下面的改进版本。


补救方法

对一个合适的模 q 来计算 p 和 ts 的模。每个字符是一个十进制数,因为 p ,t0 以及递归式 1 计算过程都可以对模 q 进行,所以可以在 O ( m ) 时间内计算出模 q 的 p 值。在时间 O( n-m+1 ) 计算出模 q 的所有 ts 值。通常选模 q 为一个素数,使得 10q 正好为一个计算机字长。

在一般情况下,采用 d 进制的字母表 { 0 ,1,... ,d - 1 } 时,所选取的 q 要满足使 dq 的值在一个计算机字长内,并调整递归式 ( 1 ) 以使对模 q 进行运算,使其成为
          
 t ( s + 1) = ( d ( ts -  T [ s+1 ] h ) + T [ s + m +1]  ) mod q
其中 h 
≡ d ^ ( m-1 ) (mod q) 。

加入模 q 后,我们已经不能通过 ts ≡ p (mod q ) 并不能说明 ts = p 。当 ts ≡ p (mod q ) 不成立时,则肯定 ts != p 。因此,当 ts ≡ p (mod q ) 时我们还需要进一步进行测试,看看 ts 是否等于  p ,因为 ts 可能是匹配的也有可能是伪匹配的。

这个算法就是有点使用hash的思想了。把模式字符串进行一个预处理,并mod,主字符串进行逐个进行简单的hash映射,然后mod比较。


伪代码如下
RABIN-KARP-MATCHER( T,P,d,q)
1 n ← length[ T ]
2 m ← length[ P]
3 h ← d^(m-1) mod q
4 p ← 0
5 t0 ← 0
6 for i ← 1 to m Preprocessing(预处理)
7 do p ← (dp + P[i]) mod q
8 t0 ← (dt0 + T[i]) mod q
9 for s ← 0 to s-m Matching( 匹配 )
10 do if p = t
11 then if P[1..m] = T[s+1..s+m] 对p 和 T 中的每个字符进行判断
12 then print "匹配"
13 if s < n - m
14 then t(s+1) ← (d (ts - T[s+1] h) + T[s+m+1]) mod q

代码实现

*Copyright(c) Computer Science Department of XiaMen University
*
*Authored by laimingxing on: 2012年 03月 04日 星期日 18:18:28 CST
*
* @desc:
*
* @history
*/
// d = 256 ; q = 127 void RABIN_KARP_MATCHER( char *T, char *P, int q)
{
assert( T && P && q > 0 );
int M = strlen( P );
int N = strlen( T );
int i, j;
int p = 0;//hash value for pattern
int t = 0;//hash value for txt
int h = 1; //the value of h would be "pow( d, M - 1 ) % q "
for( i = 0; i < M - 1; i++)
h = ( h * d ) % q; for( i = 0; i < M; i++ )
{
p = ( d * p + P[i] ) % q;
t = ( d * t + T[i] ) % q;
} //Slide the pattern over text one by one
for( i = 0; i <= N - M; i++)
{
if( p == t)
{
for( j = 0; j < M; j++)
if(T[i+j] != P[j])
break;
if( j == M )
printf("Pattern occurs with shifts: %d\n", i);
}
//Caluate hash value for next window of test:Remove leading digit,
//add trailling digit
if( i < N - M )
{
t = ( d * ( t - T[i] * h ) + T[i + M] ) % q;
if( t < 0 )
t += q;//按照书上的伪代码会出现t为负的情况,则之后的计算就失败了。
}
}
}

Rabin-Karp-Matcher 的预处理时间为 O ( m ) ,其匹配时间在最坏情况下为 O ( ( n- m + 1) m) ,
虽然 Rabin-Karp-Matcher 在最坏的情况下与朴素匹配一样,但是实际应用中往往比朴素算法快很多,应用还是很广的。

字符串匹配算法 -- Rabin-Karp 算法的更多相关文章

  1. 字符串匹配算法之 kmp算法 (python版)

    字符串匹配算法之 kmp算法 (python版) 1.什么是KMP算法 KMP是三位大牛:D.E.Knuth.J.H.MorriT和V.R.Pratt同时发现的.其中第一位就是<计算机程序设计艺 ...

  2. 字符串匹配算法之BM算法

    BM算法,全称是Boyer-Moore算法,1977年,德克萨斯大学的Robert S. Boyer教授和J Strother Moore教授发明了一种新的字符串匹配算法. BM算法定义了两个规则: ...

  3. 动画演示Sunday字符串匹配算法——比KMP算法快七倍!极易理解!

    前言 上一篇我用动画的方式向大家详细说明了KMP算法(没看过的同学可以回去看看). 这次我依旧采用动画的方式向大家介绍另一个你用一次就会爱上的字符串匹配算法:Sunday算法,希望能收获你的点赞关注收 ...

  4. 字符串匹配算法之Sunday算法(转)

    字符串匹配算法之Sunday算法 背景 我们第一次接触字符串匹配,想到的肯定是直接用2个循环来遍历,这样代码虽然简单,但时间复杂度却是Ω(m*n),也就是达到了字符串匹配效率的下限.于是后来人经过研究 ...

  5. 字符串匹配算法之Sunday算法

    字符串匹配查找算法中,最着名的两个是KMP算法(Knuth-Morris-Pratt)和BM算法(Boyer-Moore).两个算法在最坏情况下均具有线性的查找时间.但是在实用上,KMP算法并不比最简 ...

  6. 字符串匹配算法之————KMP算法

    上一篇中讲到暴力法字符串匹配算法,但是暴力法明显存在这样一个问题:一次只移动一个字符.但实际上,针对不同的匹配情况,每次移动的间隔可以更大,没有必要每次只是移动一位: 关于KMP算法的描述,推荐一篇博 ...

  7. 字符串匹配算法之kmp算法

    kmp算法是一种效率非常高的字符串匹配算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,所以简称KMP算法 算法思想 在一个字符串中查找另一个字符串时,会遇到如下图的情况 我们通常 ...

  8. 字符串匹配算法:Sunday算法

    背景 我们第一次接触字符串匹配,想到的肯定是直接用2个循环来遍历,这样代码虽然简单,但时间复杂度却是\(Ω(m*n)\),也就是达到了字符串匹配效率的下限.于是后来人经过研究,构造出了著名的KMP算法 ...

  9. 字符串匹配算法(二)-BM算法详解

    我们在字符串匹配算法(一)学习了BF算法和RK算法,那有没更加高效的字符串匹配算法呢.我们今天就来聊一聊BM算法. BM算法 我们把模式串和主串的匹配过程,可以看做是固定主串,然后模式串不断在往后滑动 ...

  10. 字符串匹配算法(三)-KMP算法

    今天我们来聊一下字符串匹配算法里最著名的算法-KMP算法,KMP算法的全称是 Knuth Morris Pratt 算法,是根据三位作者(D.E.Knuth,J.H.Morris 和 V.R.Prat ...

随机推荐

  1. ArcGIS API for Silverlight 使用GP服务实现要素裁剪功能

    原文:ArcGIS API for Silverlight 使用GP服务实现要素裁剪功能 昨天一QQ好友问了一个关于裁剪的问题,感觉自己也没有帮上什么忙,之后自己做了一个裁剪的例子,不过在做这个例子的 ...

  2. javascript继承—继承的实现原理(1)

    原文:javascript继承-继承的实现原理(1) 打算针对js的继承写一系列文章,详细的分析js里继承原理,实现方式,各种继承方式的优缺点,以及最优继承方案,还有多继承的问题等…. 面向对象的编程 ...

  3. 为什么使用Hystrix?

    分布式服务弹性框架“Hystrix”实践与源码研究(一)   文章初衷 为了应对将来在线(特别是无线端)业务量的成倍增长,后端服务的分布式化程度需要不断提高,对于服务的延迟和容错管理将面临更大挑战,公 ...

  4. Php设计模式(三):行为型模式part2

    原文详见:http://www.ucai.cn/blogdetail/7023?mid=1&f=5 可以在线运行查看效果哦! <接上文> 5.中介者模式(Mediator) : 用 ...

  5. HBase数据同步ElasticSearch该程序

    ElasticSearch的River机械 ElasticSearch本身就提供了River机械,对于同步数据. 在这里,现在能找到的官方推荐River: http://www.elasticsear ...

  6. rpm安装FAQ

    1.error: cannot create %sourcedir /usr/src/redhat/SOURCES错误的解决方案 显现error: cannot create %sourcedir / ...

  7. javascript通过数日两个日期之间的比较分离

    $(function () {  var starttime = transdate("2014-09-30 15:53:00");  var endtime = transdat ...

  8. unity资源

    unity资源集中贴 1.unity经验之谈 http://jingyan.baidu.com/article/19192ad820f17be53e570715.html 2.百度网盘,分享了一点模型 ...

  9. ASP.NET 5应用是如何运行的(3)

    ASP.NET 5应用是如何运行的(3) 设置自定义的入口程序体现应用本身与应用托管之间的分离,它使我们可以创建独立于托管环境的应用,并根据需要寄宿于任何一个我们希望的宿主程序下,对于Web应用来说这 ...

  10. C语言实现全排列

    实现全排列,递归实现 #include <stdio.h> #include <stdlib.h> ; void swap(int *a, int *b) { int m; m ...