【数据结构】字符串匹配

字符串匹配

字符串匹配是在主串中找字串所处主串的起始位置,是各大搜索引擎进行关键字查找的重要步骤之一。

1.字符串的存储结构

typedef struct {
	char ch[MaxSize];  //字符数组
	int length;	       //字符串长度
}String;

2.BF暴力匹配算法

暴力匹配不名思意,就是挨个进行比较,如果全部匹配则返回字串在主串中的位置;如果查找失败,则子串指针回退到起始位置,主串指针回退到前一步对比起始位的后一步位置,重新开始匹配,其时间复杂度最坏可以达到O(m*n)。

int Index_BF(String S, String T){
	/*暴力匹配*/
	int i = 1, j = 1;
	while (i <= S.length && j <= T.length){
		if (S.ch[i] == T.ch[j]){	//若字符匹配
			i++; j++;	  	//子串指针和主串指针同时后移
		}else{		//若不匹配
			i = i - j + 2;  //主串指针回到此次对比起始位的后一位置
			j = 1;       	//子串指针回到起始位置
		}
	}
	if (j > T.length) return i - T.length;
	return 0;
}

3.KMP匹配算法

首先获取next数组,若匹配失败的话则子串指针用next数组下对应的位置进行回退,因此可以使得时间复杂度达到O(m+n)。

(1)获取next数组

next数组的获取类似于子串自身对自身匹配,字串的首个字符匹配失败所回退的位置,对应的next[1],所以可将next[1]设成0,并在判断字符串是否相等的 if 语句中添加 j == 0 用来使当 j 等于 0 时可以让 i 后移以为,同时 j 也后移一位。
后续对next数组的设置,可以在子串与主串子针后移后,使用next[i] = j 来设置后续的next值。因此next[1] 为0 ,next[2] 为1。

void get_next(String S, int next[]){
	/*获取next数组*/
	int i = 1, j = 0;
	next[1] = 0;
	while (i < S.length){
		if (S.ch[i] == S.ch[j] || j == 0){
			i++; j++;
			next[i] = j;
		}else{
			j = next[j];
		}
	}
}
(2)获取nextval数组

当子串中存在连续的字符,如:“aaaab”,若主串的字符为“aaaacaaaab”,则在第5位会匹配失败,但是前面匹配的字符串全部相同,按照next数组的话,则子串指针会回退到next[5]所存储的位置,而 next[5] 等于 4,子串指针会移动到4,主串继续在第5位,依次类推,则会重复很多次不必要的对比,因此引入nextval数组。
nextval数组是next数组的升级版本,若子串中存在连续的字符,则后一个字符的nextval值存储前一个相同字符的索引,这样就可以跳过连续字符的不必要对比。

void get_nextval(String S, int nextval[]){
	/*获取nextval数组*/
	int i = 1, j = 0;
	nextval[1] = 0;
	while (i < S.length){
		if (S.ch[i] == S.ch[j] || j == 0){
			i++; j++;
			if (S.ch[i] != S.ch[j]){  //若两个字符不相等,则照常进行存储
				nextval[i] = j;
			}else{
				nextval[i] = nextval[j];//若两个字符相等,则设成前个索引
			}
		}else{
			j = nextval[j];
		}
	} 
}
(3)KMP匹配

KMP匹配使用next作为辅助,当主串与子串对匹配失败时,其子串指针回退的位置值可直接取nextval数组中的索引值,从而达到有效回退的作用,大大节约运算时间,使其时间复杂度达到O(m+n)。

int Index_KMP(String S, String T, int next[]){
	/*KMP算法*/
	int i = 1, j = 1;
	while (i <= S.length && j <= T.length){
		if (S.ch[i] == T.ch[j] || j == 0){
			i++; j++;
		}else{
			j = next[j];
		}
	} 
	if (j > T.length) return i - T.length;
	return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瘦瘦无感

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值