这是我参与「第五届青训营 」伴学笔记创作活动的第 17 天
串
定义
串(string )是由零个或多个字符组成的有限序列,又名叫字符 串。
一般记为s = "a1a2……an";
s是串的名称 注意单引号不属于串的内容。 a(l<i< n) 可以是字母、数字或其他字符,
i就是该字符在串中的位置 串中的字符数目n称 为串的长度 ”有限”是指长度n是一个有限的数值。
零个字符的串称为 空串 (null string), 它的长度为零,可以直接用两双引号""""表示,也可以用希腊 字母"打不来"来表示。
所谓的序列,说明串的相邻字符之间具有前驱和后继的关系。
*空格串: *是只包含空格的串。注意它与空串的区别,空格串是有内容有长度的, 而且可以不止一个空格。
*子串与主串: *串中任意个数的连续字符组成的子序列称为该串的子串,相应地, 包含子串的串称为主串。
子串在主串中的位置就是子串的第一个字符在主串中的序号
串的比较
相等
不相等比较
串的抽象数据类型
操作Index的实现算法
串的存储结构
串的存储结构与线性表相同,分为两种:
- 串的顺序存储结构
- 串的链式存储结构
串的顺序存储结构
串的顺序存储结构是用一组地址连续的存储单元来存储串中的字符序列的。
按照 预定义的大小,为每个定义的串变量分配一个固定长度的存储区。一般是用定长数组 来定义。
比如在计算机中存在一个自由存储区,叫做“堆“ 这个堆可由C语言的 动态分配函数malloc ()和free ()来管理。
串的链式存储结构
对于串的链式存储结构,与线性表是相似的,但由于串结构的特殊性,结构中的 每个元素数据是一个字符,如果也简单的应用链表存储串值,一个结点对应一个字 符,就会存在很大的空间浪费。因此,一个结点可以存放一个字符,也可以考虑存放 多个字符,最后一个结点若是未被占满时,可以用或其他非串值字符补全,如 图5-5-3所示。
当然,这里一个结点存多少个字符才合适就变得很重要,这会直接影响着串处理 的效率,需要根据实际情况做出选择。
但串的链式存储结构除了在连接串与串操作时有一定方便之外,总的来说不如顺 序存储灵活,性能也不如顺序存储结构好。
朴素的模式匹配算法
串的定位操作通常称做串的模式匹配
从下面的主串S=“goodgoogle”中,找到T="google”这个子串的位置。
用数组实现算法Index
前面我们已经用串的其他操作实现了模式匹配的算法Index。现在考虑不用串的其 他操作,而是只用基本的数组来实现同样的算法。注意我们假设主串S和要匹配的子 串T的长度存在S[0]与T[0]中。实现代码如下:
KMP模式匹配算法
DEKnuth、J.H.Morris和V.R.Pratt (其 中Knuth和Pratt共同研究,Morris独立研究)发表一个模式匹配算法,可以大大避 免重复遍历的情
况,我们把它称之为克努特一莫里斯一普拉特算法,简称KMP算 法。
KMP模式匹配算法原理
我们可以得出规律,j值的多少取决 于当前字符之前的串的前后缀的相似度。
next数组值推导
- 情况一
- 情况二
- 情况三
- 情况四
KMP模式匹配算法实现
这段代码的目的就是为了计算出当前要匹配的串T的next数组
KMP算法仅当模式与主串之间存在许多“部分匹配”的情况下 才体现出它的优势,否则两者差异并不明显。
KMP模式匹配算法改进
KMP还是有缺陷的。比如,如果我们的主串S=”aaaabcde”,子串 T=”aaaaaax“其next数组值分别为012345,在开始时,当i=5、j=5时,我们发现 “b”与“a”不相等,如图5-7-6的①,因lit j=next[5]=4,如图中的②,此时“b”与 第4位置的“a"依然不等,j=next[4]=3,如图中的③,后依次是④⑤,直到 j=next[l]=0时,根据算法,此时if J++,得到i=6、j=l,如图中的⑥
中的②③④⑤步骤,其实是多余的判断。由于T串的第二、三、 四、五位置的字符都与首位的“a”相等,那么可以用首位next[l]的值去取代与它相 等的字符后续next[j]的值,
假设取代的数组为nextval,增加了加粗部分,代码如下:
nextval数组值推导
总结
改进过的KMP算法,它是在计算出next值的同时,如果a位字符与它next 值指向的b位字符相等,则该a位的nextval就指向b位的
nextval值,如果不等,则 该a位的nextval值就是它自己a位的next的值。