【数据结构】—— chapter 04 串

4.1 串的定义和实现

4.1.1 串的定义

在这里插入图片描述在这里插入图片描述
串是一种特殊的线性表,数据元素之间呈线性关系 ;
串的数据对象限定为字符集(如中文字符、英文字符、数字字符、标点字符等);
串的基本操作,如增删改查等通常以子串为操作对象

4.1.2 串的基本操作

在这里插入图片描述

4.1.3 串的存储结构

在这里插入图片描述

1. 顺序存储
在这里插入图片描述
在这里插入图片描述
2. 链式存储
在这里插入图片描述
3. 基于顺序存储实现基本操作
在这里插入图片描述
顺序存储结构
在这里插入图片描述

1. SubString(&Sub,S,pos,len):求子串。用Sub返回串S的第pos个字符起长度为len的子串。

在这里插入图片描述

2. StrCompare(S,T):比较操作。若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0。

在这里插入图片描述

3.Index(S,T):定位操作。若主串S中存在与串T值相同的子串,则返回它在主串S中第一次出现的 位置;否则函数值为0。

在这里插入图片描述

4.2 串的模式匹配

4.2.1 简单的模式匹配算法

子串的定位操作通常称为串的模式匹配,它求的是子串(常称模式串)在主串中的位置。这里采用定长顺序存储结构,给出一种不依赖其他串操作的暴力匹配算法。
在这里插入图片描述在这里插入图片描述
算法性能分析:
在这里插入图片描述在这里插入图片描述

4.2.1 改进的模式匹配算法 —— KMP算法

朴素(简单)模式匹配算法的缺点:当某些子串与模式串能部分匹配时,主串的扫描指针i经常回溯,导致时间开销增加。
改进思路:主串指针不回溯,只有模式串指针回溯
kmp算法的关键:next数组。

1. 步步模拟得到next数组 + Kmp算法代码

下面以 ‘google’ 为例进行说明:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
最终得到:
在这里插入图片描述

这样就可以得出next数组了
在这里插入图片描述
KMP算法实现:
在这里插入图片描述

2. next数组 (手算)

串的前缀:包含第一个字符,且不包含最后一个字符的子串
串的后缀:包含最后一个字符,且不包含第一个字符的子串
next数组手算方法:当第j个字符匹配失败,由前1~j-1个字符组成的串记为S,则 next[j]=S的最长相等前后缀长度+1。特别地,next[1] = 0、next[2] = 1。

练习
在这里插入图片描述

3. next数组(机算)

上面手算next数组很快捷,但是想用代码实现的时候,却发现无从下手。下面尝试推理求解的科学步骤。
下图是next数组的公式,与上面的手算公式其实是一样的。
在这里插入图片描述

用例子理解:

j123456789
模式abaabcaba
next[j]011223???

求next[7],因为next[6]=3,说明p1p2=p4p5,因此比较p3、p6。
如果相等,则next[7]=next[6]+1。
如果不相等,就寻找更短的最长相等前后缀。
显然p3与p6不等,去寻找更短的最长相等前后缀,next[3]=1,所以比较p1、p6,p1与p6不等,ok,再寻找更短的,next[1]=0,没有p0,无法比较下去。那么next[7]=1。
求next[8],已知next[7] = 1,因p7=p1(都是a),所以next[8] = next[7] + 1 = 2;
求next[9],已知next[8] = 2,因p8=p2,所以next[9] = next[8] + 1 = 3。
注:next数组实现的代码在4.中。

4. next数组算法代码 + Kmp算法代码

在这里插入图片描述
KMP算法仅在主串与子串有很多 “部分匹配” 时才显得比普通算法快得多,其主要优点是主串不回溯。

4.2.3 KMP算法的进一步优化 —— nextval数组

前面定义的next数组在某些情况下尚有缺陷,还可以进一步优化。
如下图1所示,模式串‘aaaab’在和主串进行匹配时,当i=4,j=4时发生失配,根据之前的next数组接下来要进行如图2、3、4的3次比较,很明显,这三次比较是无意义的。
其实直接从i=5、j=1开始比较就行。我们发现,将字母相同的next[j]改为一致的(从左向右),仍然可以实现匹配,而且还减少了许多不必要的比较。那么我们就可以得到nextval数组,如下图5.
在这里插入图片描述 在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
nextval数组实现代码:

//nextval数组
void get_nextval(SString T, int nextval[]) {
	int i = 1, j = 0;
	nextval[1] = 0;
	while (i < T.length) {
		if (j == 0 || T.ch[i] == T.ch[j]) {
			i++;
			j++;
			if (T.ch[i] != T.ch[j])   nextval[i] = j;
			else  nextval[i] = nextval[j];
		}
		else
			j = nextval[j];
	}
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值