精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-12-04
<!----><!----> <!----> 字符串匹配问题( 1 )—— Rabin-Karp 算法 <!---->1. <!---->问题描述 给定目标字符串 T[0..n-1] (基于 0 的数组,数组长度为 n ),和模式串 P[0..m-1] ,问 P 可否匹配 T 中的任意子串,如果可以,返回匹配位置。 <!---->2. <!---->问题分析 <!----> <!---->直观分析 brute-force 的蛮力法,适用于较小规模的字符串匹配。 <!----> <!---->优化 主要介绍 3 种优化办法,分别具体为: Rabin-Karp 算法,有限自动机和 KMP 算法。将分为 3 篇博文分别讨论。本小节主要介绍 Rabin-Karp 算法。 <!----> <!---->得出算法 Rabin-Karp 算法(以下简称为 RK 算法),是基于这样的思路:即把串看作是字符集长度进制的数,由数的比较得出字符串的比较结果。例如,给定字符集为∑ ={0,1,2,3,4,5,6,7,8,9} ,∑长度为 d=10 ,那么任何以∑为字符集的串都可看作 d (此处为 10 )进制的数。 记模式串 P[0..n-1] 对应的数值为 P , T[0..n-1] 所有长度为 m 的子串对应的数值为 ts ,设 P 和 T 都是基于字符集长度为 | ∑ |=d 的字符串。 那么, ts 即为 T[s..s+m] 对应的数值,这里 0<=s<=n-m-1 。 P = P[m]+d*(P[m-1]+d*(P[m-2]+..))) 同样 t0 也可类似求得。 最重要的是如何从 ts 求出 ts+1 。 ts+1 =T[s+m]+d*(ts +dm-1 *T[s]) 注:此处是该算法的关键,即在常数时间内能够计算出下一个 m 长度的字串对应的数值。初看比较抽象,举个例子就比较明白了,设 x=12345 ,现在是已知长度为 3 的数值 234 ,现在要求 345 对应的数值,可以这样来得到: 345 = 5 + 10*(234-102 *2) <!---->3. <!---->算法描述 求出所有 m 长度子串所对应的数值,对数值进行比较,继而得出子串是否匹配。当模式串长度很大时,这时对应的数值会很大,比较起来比较麻烦,可使用对一个大奇数取模后进行比较。 <!---->4. <!---->具体实现 这里实现的只是m值较小时的情形,大整数需要特定的类的支持(如可自定义大整数类),选取10进制的数是为了方便起见,当然字母也是OK的。
#include "iostream" #include "string" #include "cmath" using namespace std; // get the value of the character in the set int getV(char p, string set) { for(int i=0; i<set.length(); i++) { if (p==set[i]) return i; } return -1; } // d is the size of the character set int RK(string T, string P,string set) { int d = int(set.length()); int n = T.length(); int m = P.length(); int h = pow(double(d), m-1); int p=0; int t = 0; for(int i=0; i<m; i++) { p = d*p + getV(P[i],set); t = d*t + getV(T[i], set); } for (int s=0; s<=n-m; s++) { cout<<"p,t is "<<p<<","<<t<<endl; if (p==t) return s; if (s<n-m) t = getV(T[s+m],set)+d*(t-h*getV(T[s],set)); } return -1; } int main() { // set is the character set string set= "0123456789"; // pattern P string P = "2365"; // T is the string to match string T = "258569236589780"; int i = RK(T, P, set); cout<<"the postition is:"<<i<<endl; return 0; }
<!----><!----> <!---->5. <!---->参考资料 [1] Thomas H. Cormen Introduction to Algorithms
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-11-15
学习了,感谢!顺便问几个问题:
1. “记模式串 P[0..n-1] 对应的数值为 P ”这一句是否应该是p[0..m-1]? 2. 公式“ts+1 =T[s+m]+d*(ts +dm-1 *T[s])”是否应该是“ts+1 =T[s+m]+d*(ts -dm-1 *T[s])”?因为我手工推导了一次,发现自己推出的是减号,而且您的文章中计算“345 = 5 + 10*(234-102 *2)”用到的也是减号。 |
|
返回顶楼 | |
浏览 6886 次