TD04-串


关于数组及相关特殊矩阵的压缩存储内容 见书本(书本记录更方便)。

一、串的定义

字符串 简称 串,计算机上非数值处理的对象基本上都是字符数据
串:由零个或多个字符串组成
长度:串中字符个数n
空串:n=0
子串:子序列
主串:包含子序列的串
串中位置:某个字符串在串中的序号
子串在主串中的位置:子串的第一个字符串在主串中的位置
空格串:一个或多个空格组成的串(空格串不是空串,其长度为串中空格字符的个数)
A=‘China Beijing’,B=‘Beijing’,长度分别为:13,7。B是A的子串,B在A中的位置是7。

串与线性表 相似
区别:
数据对象:串—字符集
基本操作对象:串—子串;线性表—单个元素

二、串的存储结构

1.存储结构

顺序存储结构

//------串的定长顺序存储结构
#define MAXLEN 255			//串的最大长度
typedef struct {
	char ch[MAXLEN + 1];	//存储串的一维数组(这里顺序存储的字符串是从下标为1的数组分量开始存储的,下标0闲置不用)
	int length;				//串的当前长度
}SString;

堆分配存储表示

//------堆分配存储表示
typedef struct {
	char* ch;				//按串长分配存储区,ch指向串的基地址
	int length;				//串长度
}HString;

链式存储

//------串的链式存储
#define CHUNKSIZE 80		//块的大小
typedef struct Chunk {
	char ch[CHUNKSIZE];
	struct Chunk* next;
}Chunk;
typedef struct {
	Chunk* head, * tail;	//串的头指针,尾指针
	int length;				//串的当前长度
}LString;

2.暴力算法(BF算法)

指针后退重新开始匹配:
i = i - j + 2;
j = 1;

匹配子串在主串位置:
i - T.length;

举例:
在这里插入图片描述

//暴力匹配算法(BF算法)
int Index(SString S, SString 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;
	else
		return 0;
}

时间复杂度O(mn),n:主串长度;m:子串长度。

3.KMP算法(改进的模式匹配算法)

1、前缀:除最后一个字符外,字符串的所有头部子串
2、后缀:除第一个字符外,字符串的所有尾部子串
3、部分匹配值:前缀后缀的最长相等前后缀长度
如:ababa 前缀:a ab aba abab;后缀:a ba aba baba,最长相等前后缀长度3。
同理:a—0,ab—0,aba—1,abab—2,ababa—3
所以字符串‘ababa’的部分匹配值为00123
4、部分匹配值(Partial Match,PM)表
在这里插入图片描述
5、子串需要向后移动个数
移动位数=已匹配的字符数-对应的部分匹配值

6、算法改进:
已知:右移位数=已匹配的字符数-对应的部分匹配值
写成:Move = ( j - 1 ) - PM [ j - 1 ]
使用部分匹配时,每匹配失败就要找前一个元素的部分匹配值,这样使用不方便,所以将PM表右移一位,即:
在这里插入图片描述
(1)第一个元素 右移后空缺用-1表示,若是第一个元素匹配失败,直接加一,即将子串相对右移,而不需要计算子串移动的位数
(2)最后一个元素 右移后溢出,因为在原来子串中,最后一个元素的部分匹配值是给下一个元素使用,而最后一个元素没有下一个元素,可舍去。
上式写成:Move=(j-1)-next[j]
相当于子串的 j 回到:j=j-Move=j-((j-1)-next[j])=next[j]+1
即next数组更新:
在这里插入图片描述
7、next函数公式:
在这里插入图片描述
8、思绪理解
(1)
在这里插入图片描述
(2)例题中的
在这里插入图片描述
9、子串next

//子串next
void  get_next(SString T, int next[]) {
	int i = 1, j = 0;
	next[1] = 0;
	while (i < T.length) {
		if (j == 0 || T.ch[i] == T.ch[j]) {
			++i;
			++j;			//1
			next[i] = j;	//2,若pi=pj,则next[j+1]=next[j]+1
		}
		else
		{
			j = next[j];
		}
	}
}

10、KMP算法

//KMP
int Index_KMP(SString S, SString T, int next[]) {
	int i = 1, j = 1;
	while (i < S.length && j < T.length) {
		if (j == 0 || S.ch[i] == T.ch[j]) {		//0是当比较第一个字符时
			++i;
			++j;
		}
		else
			j = next[j];
	}
	if (j > T.length)
		return i - T.length;
	else
		return 0;
}

时间复杂度O(m+n),n:主串长度;m:子串长度。

4.MKP算法的进一步优化

修正一些相等的字符,避免重复

一路和next[j]比较
不等,取原来的next[j],即不变
若相等,继续向前比较,直到找到不等,取不等位的next,或直到j=0。

例:
在这里插入图片描述
子串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];
		}
	}
}

三、错题

1、已知字符串S为’ abaabaabacacaabaabcc’,模式串t为’abaabc’. 采用KMP算法进行匹配,第一次出现“失配”(s[i]≠t[j]) 时,i=j=5,则下次开始匹配时,i和j的值分别是( )。

A. i=1,j=0

B. i=5,j=0

C. i=5,j=2

D. i=6,j=2
在这里插入图片描述

2、设主串T=’ abaabaabcabaabc’,模式串S= ‘abaabc’,采用KMP算法进行模式匹配,到匹配成功时为止,在匹配过程中进行的单个字符间的比较次数是 ( )。

A.9

B.10

C.12

D.15
在这里插入图片描述


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值