第四章 串(数据结构与算法)

简介: 第四章 串(数据结构与算法)

配套资源下载

数据结构资源下载导航【数据结构】

第4章串

4.1应用实例

文本编辑器

4.2串及其运算

4.2.1串的基本概念

1.串的概念

串(string)是由零个或多个字符组成的有限序列,一般记作:S=‘a1a2a3…an

其中
(1) S 为串的名字

(2)单引号括起来的字符串序列为串的值;将串值括起来的单引号本身不属于串,它的作用是避免串与常数与标识符混淆

(3)an(1≤i≤n)可以是字母、数字或其他字符

(4)n为串中字符的字数,称为串的长度。
2.常用术语

①空串

②空格串

③子串

④主串

⑤前缀子串

⑥后缀子串

⑦位置

⑧串相等

⑨模式匹配

4.2.2 串的基本运算

1.串的抽象数据类型定义

串的抽象数据类型定义如下。

ADT String{
数据对象:D={ai,lai∈CharacterSet,i=1,2,…,n,n>0}

数据关系:R={<ai-1|a,>lai-1,ai∈D,i=2,3,n}

基本操作:

(1) StrAssign(S,chars)

初始条件:chars是字符串常量。

操作结果:生成一个串S,并使其串值等于chars。

(2)StrCopy(S.T)

初始条件:串T存在

操作结果:将串T的值献给串S

(3) StrLength(S)

初始条件:串S存在

操作结果:返回串S的长度,即串S中字符的个数

(4) Strlnsert(S,pos,T)

初始条件:串S和T存在,I≤pos≤StrLength(S)+1

操作结果:在串S的第pos个字符之前插入串T

(5) StrDelete(S.pos,len)

初始条件:串S存在,1≤pos≤Strlength(S),且0≤len≤Sulengh(S)-pos+l

操作结果:在串S中删除从第pas个字符开始连续len个字符后形成的子串,

(6) StrCompare(S,T)

初始条件:串S和T存在。

操作结果:若串S和串了相等,则返回值等于0;否则返回串S和串下第一个不相等字符的ANSI码值之差

(7) StrCat(S,T)

初始条件:串S和T存在。S足够长

操作结果:将串T的值连接在串S的后面。

(8) SubString(T,S.pos.len)

初始条件:串S存在,1≤lpos≤StrLength(S),且0≤lensStrLength(S)-pos+1

操作结果:截取串S中从第pos个字符开始连续len个字符形成的子串,并赋值给串T,

(9) StrIndex(S,pos, T)

初始条件:串S和T存在,1≤pos≤StrLength(S):

操作结果:若串S中从第pos个字符后存在与串T相等的子串,则返回串T在申S中第pos个字符后首次出现的位置;否则返回0。

(10) StrReplace(S,T,V)

初始条件;串S、串T和串V存在,且串T是非空申。

操作结果:用串V替换串S中出现的所有与串T相等的不重叠的子串。

(11) StrEmpty(S)

初始条件:串S存在。

操作结果:若串S为空串,则返回TRUE;否则返回FALSE

(12) StrClear(S)

初始条件;串S存在

操作结果:将S清为空串,

(13) StrDestroy(S)

初始条件;串S存在

操作结果:销毁串S

}ADT Siring

2. 串的基本运算示例

4.3串的存储结构及实现

4.3.1 定长顺序串

1.定长顺序串存储结构

定长顺序串存储结构如下:

#define MAXLEN 50//字符串的最大长度
typedef struct{
  char ch[ MAXLEN+1];//存储字符串的一维数组,每个分量存储一个字符,第0号单元不使用  
  int len;//字符串的长度
}SString;

串的实际长度可在预定义长度MAXLEN的范围内随意变动,超过MAXLEN,串值被舍去,称为“截断”

4.3.2 堆串

1.堆串存储结构

typedef struct{
  char * ch;//若是非空串,则指向串的起始地址;否则ch为NULL
  int len;//字符串的长度
}HString;

为了便于理解和讨论,这里在给串分配存储空间时,在实际串长的基础上多分配一个存储间,且连续空间的第0号单元不使用。

4.3.3 块链串

4.3.3块链串
由于串是一种符殊的线性表,所以存储字符串的串值除了可以采用顺序存储结构,也可以用链式存储结构。

在串的链式存储结构中,链表的每个结点既可以存放一个字符,也可以存放多个字符,每个结点称为“块”,整个链表称为“块链结构”。

块链串存储结构如下:

#define BLOCK_SIZE 4//每个结点存放字符个数为4
typedef struct block{
  char ch[ BLOCK_SIZE];
  struet block * next;
} Block;
typedef struct{
  Block * head;//块链串的头指针
  Block * lail;//块链串的尾指针
  int len;//字符串长度
}LString;

4.4串的模式匹配

4.4.1 BF模式匹配算法

蛮力匹配

4.4.2 KMP模式匹配算法

[KMP算法思想]Knuth-Mrris-Pratt算法(简称KMP),是由D.E.Knuth.JHMorris和VR.Pratt共同提出的一个改进算法。KMP算法是模式匹配中的经典算法,和BF算法相比,KMP算法的不同点是消除BF算法中主串S指针回溯的情况,从而完成串的模式匹配,这样的结果使得算法的时间复杂度为O(n+m)。


[KMP算法描述]KMP算法每当一趟匹配过程中出现字符比较不等时,主串S中的i指针不需回溯,而是利用已经得到的“部分匹配”结果将模式向右“滑动”尽可能远的一段距离后,继续进行比较。


回顾图4.5的匹配过程示例,在第三趟的匹配中,当i=7、j=5字符比较不等时,又从i4、j=1重新开始比较。然后,经过仔细观察可发现,在i=4和j=1,i=5和j=1以及i=6和j=1这三次比较都是不必进行的。因为从第三趟部分匹配的结果就可得出,主串中第4、5、6个字符必然和模式串中的第2、3、4个字符相等,即都是"b’、'c、‘a’。因为模式串中的第一个字符是’a,因此它无需再和这三个字符进行比较,而仅需将模式串向右滑动三个字符的位置继续进行i=7、j=2时的字符比较即可。同理,在第一趟的匹配中出现字符不等时,仅需将模式向右移动两个字符的位置进行i=3、j=1时的字符比较。因此,在整个匹配的过程中,i指针没有回溯,如图4.7所示。


一般情况下,假设主串为’S1S2…Sn’,模式串为’T1T2…Tn’,从上例的分析可知,为了实现KMP算法,需要解决以下问题,当匹配过程中产生“失配”(即Si≠Ti)时,模式串“向右滑动”可滑动的距离有名远,也就是说,当主串中字符Si,与模式串中字符Tj"失配”时,主串中字符Si( i 指针不回溯)应与模式串中哪个字符再进行比较?


假设此时主串中字符Si应与模式中字符Tk(k<j)继续进行比较,则主串S和模式串T满 如下关系。

S=S1S2…Si-j+1Si-j+2…Si-k+1…Si-1Si …Sn

T=            T1    T2    …Tj-k+1…Tj-k+2…

T=                               T1     …Tk-1…


可以看出,若模式串中存在’T1T2…Tk-1’=‘Tj-k+1Tj-k+2…Tj-1’,且满足1<k<j,则当匹配过程中Si≠Tj 时,仅需将模式串向右滑动至第k个字符和主串中第i个字符对齐,匹配仅需从Si、Tk的比较起继续进行,无需i指针的回溯。在匹配过程中为了尽可能“滑动”远一段的距离,因而应选择满足条件较大的k值。


若令next[j]=k,则next[]表明当模式中第j个字符与主串中相应字符“失配”时,在模式中需重新和主串中该字符进行比较的字符的位置。由此可引出模式串的next函数的定义:


由此可见next函数的计算仅和模式串本身有关,而和主串无关。其中’T1T2…Tk-1’是’T1T2…Tj-1‘’ 的真前缀子串,'Tj-k+1Tj-k+2…Tj-1’是’T1T2…Tj-1’的真后缀子串。当next函数定义中的集合不为空时 next[j]的值等于串’T1T2…Tj-1’的真前缀子串和真后缀子串相等时的最大子串长度+1。

通过以上分析,推导出模式串’abaabcac’的next值的计算过程如表4.1所示。

(1)当j=1时,由定义得知,next[1]=0;

(2)当j=2时,满足1<k<j的k值不存在,由定义得知next[2]=1




4.5实例分析与实现

4.5.1串的实例分析

4.5.2简单文本编辑软件的实现

4.6算法总结

(1)字符串是一种特殊的线性表,器特殊性在于组成线性表的数据元素仅是一个单字符

(2)字符串常用的存储方式有定长顺序串、堆串和块链串三种。

(3)顺序串是以一维数组作为存储结构,其运算实现方法类似于线性表的顺序存储结构

(4)堆串是以动态一维数组作为存储结构,其运算实现方法和顺序串在存储管理上有所不同。

(5)块链串以链表作为存储结构,其运算实现方法类似于链表。

(6)串的模式匹配算法是本章的难点,BF模式匹配算法处理思路简单,但由于需要进行失配后主串回溯的处理,故而时间复杂度较高。改进的KMP模式匹配算法计算失配后模式串向右滑动的最大位置,由于失配后无回溯,故而匹配速度较高。

习题

相关文章
|
1月前
|
存储 人工智能 算法
第四章 串【数据结构与算法】【精致版】
第四章 串【数据结构与算法】【精致版】
63 0
|
7月前
|
存储 算法
【AcWing算法基础课】第二章 数据结构(部分待更)(1)
e数组存储每个结点的值,ne数组存储每个结点的指向的下一个结点。
59 0
|
7月前
|
存储 算法 C++
【AcWing算法基础课】第二章 数据结构(部分待更)(3)
路径压缩:查找时,如果还没有找到目标值的父结点时,将路径上每个点的父结点,在向上寻找过程中更新记录。
64 0
|
7月前
|
存储 算法
【AcWing算法基础课】第二章 数据结构(部分待更)(2)
给定一个长度为 N 的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。
57 0
|
10月前
|
算法
2022 数据结构与算法《王道》学习笔记 (十一)KMP算法 详细归纳总结 改进的模式匹配算法
2022 数据结构与算法《王道》学习笔记 (十一)KMP算法 详细归纳总结 改进的模式匹配算法
2022 数据结构与算法《王道》学习笔记 (十一)KMP算法 详细归纳总结 改进的模式匹配算法
|
8月前
|
存储 算法 安全
数据结构与算法丨串 2
数据结构与算法丨串
67 0
|
8月前
|
存储 自然语言处理 算法
数据结构与算法丨串 1
数据结构与算法丨串
161 0
|
10月前
|
存储 人工智能 算法
2022 数据结构与算法《王道》学习笔记 (十)串 KMP算法 串的总结 课后习题笔记
2022 数据结构与算法《王道》学习笔记 (十)串 KMP算法 串的总结 课后习题笔记
数据结构一个小白的练级之路【链表的分割】题目参考
数据结构一个小白的练级之路【链表的分割】题目参考
|
C语言 C++ 容器
C++ primer 复习 第三章 字符串,向量和数组(1)
C++ primer 复习 第三章 字符串,向量和数组
C++ primer 复习 第三章 字符串,向量和数组(1)