字符串匹配是常见的面试、笔试题,这里给出3种方法。
1、轮询搜索
首先将匹配串和模式串左对齐,然后从左向右一个一个进行比较,如果不成功则匹配串向右移动一个单位。
//轮询
int Search1(char *p1,char *p2)
{
int n=strlen(p1);
int m=strlen(p2);
int i=0,j=0;
while(i<n)
{
if(p1[i]!=p2[j])
{
j=0;//这一步很重要
i++;
}
else
{
j++;
i++;
}
if(j==m)//找到了一个
{
return i-m;
}
}
return -1;
}
2、利用string类中的find函数
int Search(char *p1,char *p2)
{
string s1(p1),s2(p2);
return s1.find(s2);
}
3、Sunday匹配法
算法概述编辑
字符串模式匹配中超越BF、KMP和BM的算法
sunday算法的概念如下:
Sunday算法是Daniel M.Sunday于1990年提出的一种比BM算法搜索速度更快的算法。其核心思想是:在匹配过程中,模式串并不被要求一定要按从左向右进行比较还是从右向左进行比较,它在发现不匹配时,算法能跳过尽可能多的
字符以进行下一步的匹配,从而提高了匹配效率。
假设在发生不匹配时S[i]≠T[j],1≤i≤N,1≤j≤M。此时已经匹配的部分为u,并假设字符串u的长度为L。如图1。明显的,S[L+i+1]肯定要参加下一轮的匹配,并且T[M]至少要移动到这个位置(即模式串T至少向右移动一个字符的位置)。
分如下两种情况:
(1) S[L+i+1]在模式串T中没有出现。这个时候模式串T[0]移动到S[L+i+1]之后的字符的位置。如图2。
(2)S[L+i+1]在模式串中出现。这里S[L+i+1]从模式串T的右侧,即按T[M-1]、T[M-2]、…T[0]的次序查找。如果发现S[L+i+1]和T中的某个字符相同,则记下这个位置,记为k,1≤k≤M,且T[k]=S[L+i+1]。此时,应该把模式串T向右移动M-k个字符的位置,即移动到T[k]和S[L+i+1]对齐的位置。如图3。
Sunday算法思想跟BM算法很相似,在匹配失败时关注的是文本串中参加匹配的最末位字符的下一位字符。如果该字符没有在匹配串中出现则直接跳过,即移动步长= 匹配串长度+1;否则,同BM算法一样其移动步长=匹配串中最右端的该字符到末尾的距离+1。
2算法实例编辑
现举个例子来说明:
比如:
匹配串:O U R S T R
O N G X S E A R C H
模式串:S E A R C H
这里我们看到O-S不相同,我们就看匹配串中的O在模式串的位置,没有出现在模式串中。
匹配串:O U R S T R O N G X S E A R C H
模式串: _ _ _ _ _ _ _ _S E A R C H
移动模式串,使模式串的首字符和O的下一个字符对齐。
匹配串:O U R S T R O N G X S E A
R C H
模式串:_ _ _ _ _ _ _ _ S E A R C H
继续比较,N-S不相同,字符R出现在模式串,则后移模式串,将把它们对齐
匹配串:O U R S T R O N G X S E A
R C H
模式串: _ _ _ _ _ _ _ _ _ _ _ S E A
R C H
int sunday(const char* p1, const char* p2)
{
int n = strlen(p1);
int m = strlen(p2);
int next[256] = {0}; //可以接受任意字符
for (int j = 0; j < 256; ++j)
next[j] = m + 1;
for (int j = 0; j < m; ++j)
next[p2[j]] = m - j; //记录字符到最右段的最短距离+1
//例如:p2 = "abcdefb"
//next = {7 1 5 4 3 2 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8}
int pos = 0;
while (pos < (n - m + 1)) //末端对齐
{
int i = pos;
int j;
for (j = 0; j < m; ++j, ++i)
{
if (p1[i] != p2[j])
{
pos += next[p1[pos + m] ]; //p1[pos + m]
//不等于就跳跃,跳跃是核心
break;
}
}
if ( j == m ) //找到了
return pos;
}
return -1;
}
更详细的匹配算法请见http://dsqiu.iteye.com/blog/1700312