字符串匹配

字符串匹配是常见的面试、笔试题,这里给出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 Sunday算法不匹配的情况
分如下两种情况:
(1) S[L+i+1]在模式串T中没有出现。这个时候模式串T[0]移动到S[L+i+1]之后的字符的位置。如图2。
图2 Sunday算法移动的第1种情况
(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。
图3 Sunday算法移动的第2种情况
依次类推,如果完全匹配了,则匹配成功;否则,再进行下一轮的移动,直到 主串S的最右端结束。该算法最坏情况下的 时间复杂度为O(N*M)。对于短模式串的匹配问题,该算法执行速度较快。
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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值