字符匹配问题(1)——Rabin-Karp算法

字符串匹配问题( 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] 对应的数值为 PT[0..n-1] 所有长度为 m 的子串对应的数值为 ts ,设 PT 都是基于字符集长度为 ||=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

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值