数据结构学习日记七:串的匹配

数据结构学习笔记

十、串的匹配

10.1 直接调用strstr

10.2 KMP算法

把正常的O(n*m)变成O(n+m)。

10.2.1 人为计算match[]数组(next[])

KMP计算match

计算过程:从两侧找两个相同的子串,有则等于(长度-1);否则都是-1

1、第一位始终是 -1;

2、第二位因为ab,所以 -1;

3、第三位同理;

4、第四位可以找到aa,所以填 0;

5、第五位可以找到ab和ab,所以填 1;

6、第七位可以找到abca和abca,所以填 3;

10.2.2 当匹配失败,怎么回退

KMP回退过程

求match[]的时候,就保证了绿色段[0…match[p-1]]和紫色段[m…p-1]是相同的字符。

当在p处匹配失败时,为了实现主串指针 S 不回退,我们应该把模式串向后移,移到绿色和紫色重叠。因为前几位已经确保匹配成功了,可以继续从match[p-1]+1的位置出发继续匹配。

从模式串指针P的角度看,就是P回退到match[p-1]+1的位置。

10.2.3 实现match[]的原理

1、假设已知match[j-1],即绿色段和紫色段相同。

假设已知match[j-1]

2、查看match[j-1]+1和 j 是否相等。

求next[]数组第二步

如果相等,说明match[j] ≥ match[j-1] +1

假设相等则推翻match[j-1]的值

假设相等,那么就可以反过来去推match[j-1]的值,发现现在match[j-1]的值比之前多了。显然这是不可能的。所以可以确定

match[j] = match[j-1] +1

如果不相等,可以继续拆成更小的子列。拿着最前段绿色+?和最后面紫色段+?去比较。下图中应该拿 j 和 match[match[j-1]]+1 作比较。

如果新增j不相等

此过程是递归的循环的。

typedef int Position;
#define NotFound -1

void BuildMatch(char* pattern, int* match){
	int i,j;
	int m = strlen(pattern);
	match[0] = -1;
	for(j=1; j<m; j++){
		i = match[j-1];
		while((i>=0) && (pattern[i+1] != pattern[j]))
			i = match[i];	//不相等,一直回退。直到 i等于-1
		if(pattern[i+1] == pattern[j])
			match[j] = i+1;	//match[j] = match[j-1] +1
		else match[j] = -1;
	}
}

Position KMP(char* string, char* pattern){
    int n = strlen(string);
    int m = strlen(pattern);
    int s, p, *match;
    if(n < m) return NotFound;
    match = (int *)malloc(sizeof(int) * m);
    BuildMatch(pattern, match);
    s = p = 0;
    while(s<n && p<m){
        if(string[s] == pattern[p])	{s++; p++}//匹配
        else if(p > 0) p = match[p-1]+1;//不匹配,p要回退,s不动
        else s++;	//不匹配,且p在0处,就要改s
    }
    return (p == m) ? (s-m) : NotFound;//如果P走到m,说明完全匹配
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值