五、串(字符串)

目录

1. 串的定义

2. 串的比较

3. 串的抽象数据类型

4. 串的存储结构

串的顺序存储结构

串的链式存储结构

5. 朴素的模式匹配算法

6. KMP模式匹配算法

KMP模式匹配算法原理

next数组值推导

KMP模式匹配算法实现

KMP模式匹配算法改进

nextval数组值推导 

7. 总结


串(string)是由零个或多个字符组成的有限序列,又名叫字符串

1. 串的定义

串(string)是由零个或多个字符组成的有限序列,又名叫字符串。
一般记为s="a1a2……an"(n≥0),其中,s是串的名称,用双引号(有些书中也用单引号)括起来的字符序列是串的值,注意单引号不属于串的内容。ai(1≤i≤n)可以是字母、数字或其他字符,i就是该字符在串中的位置。串中的字符数目n称为串的长度,定义中谈到"有限"是指长度n是一个有限的数值。零个字符的串称为空串(null string),它的长度为零,可以直接用两双引号“”表示,也可以用ø来表示。所谓的序列说明串的相邻字符之间具有前驱和后继的关系
空格串和空串是不一样的;主串包含子串;

2. 串的比较

ASCII编码:8位;Unicode编码:16位,前256个字符与ASCII码完全相同。

在C语言中比较两个串是否相等,必须是它们串的长度以及它们各个对应位置的字符都相等时,才算是相等。

不用把整个串全比完,挨个比较直到有一个字符不等就可得出大小了。

3. 串的抽象数据类型

串的逻辑结构和线性表很相似,不同之处在于串针对的是字符集,也就是串中的元素都是字符,哪怕串中的字符是"123"这样的数字组成,或者"2010-10-10"这样的日期组成,它们都只能理解为长度为3和长度为10的字符串,每个元素都是字符而已。

线性表更关注的是单个元素的操作,比如查找一个元素,插入或删除一个元素,但串中更多的是查找子串位置、得到指定位置子串、替换子串等操作。

对于不同的高级语言,其实对串的基本操作会有不同的定义方法,所以在用某个语言操作字符串时,需要先查看它的参考手册关于字符串的基本操作有哪些。不过还好,不同语言除方法名称外,操作实质都是相类似的。 

使用这些基本操作函数可扩展实现更多的操作函数。

4. 串的存储结构

串的存储结构与线性表相同,分为两种。

串的顺序存储结构

串的顺序存储结构是用一组地址连续的存储单元来存储串中的字符序列的。按照预定义的大小,为每个定义的串变量分配一个固定长度的存储区。一般是用定长数组来定义。

串的链式存储结构

对于串的链式存储结构,与线性表是相似的,但由于串结构的特殊性,结构中的每个元素数据是一个字符,如果也简单的应用链表存储串值,一个结点对应一个字符,就会存在很大的空间浪费。因此,一个结点可以存放一个字符,也可以考虑存放多个字符,最后一个结点若是未被占满时,可以用"#"或其他非串值字符补全。

这里一个结点存多少个字符才合适就变得很重要,这会直接影响着串处理的效率,需要根据实际情况做出选择。

串的链式存储结构除了在连接串与串操作时有一定方便之外,总的来说不如顺序存储灵活,性能也不如顺序存储结构好。

5. 朴素的模式匹配算法

子串的定位操作通常称做串的模式匹配

简单的说,就是对主串的每一个字符作为子串开头,与要匹配的字符串进行匹配。对主串做大循环,每个字符开头做T的长度的小循环,直到匹配成功或全部遍历完成为止。

 

在实际运用中,对于计算机来说,处理的都是二进位的0和1的串,一个字符的ASCII码也可以看成是8位的二进位01串,汉字等所有的字符也都可以看成是多个0和1串。再比如像计算机图形也可以理解为是由许许多多个0和1的串组成。所以在计算机的运算当中,模式匹配操作可说是随处可见,而刚才的这个算法,就显得太低效了。

6. KMP模式匹配算法

三位前辈,D.E.Knuth、J.H.Morris 和V.R.Pratt(其中Knuth和Pratt共同研究,Morris 独立研究)发表一个模式匹配算法,可以大大避免重复遍历的情况,我们把它称之为克努特—莫里斯—普拉特算法,简称 KMP算法。

KMP模式匹配算法原理

主串中的 i 值不回溯,也就是不可以变小,那么要考虑的变化就是字串中的 j 值了。通过观察也可发现,我们屡屡提到了 T 串的首字符与自身后面字符的比较,发现如果有相等字符,j 值的变化就会不相同。也就是说,这个 j 值的变化与主串其实没什么关系,关键就取决于T串的结构中是否有重复的问题。

比如,T="abcdex",当中没有任何重复的字符,所以 j 就由 6 变成了1。而如果T="abcabx",前缀的"ab"与最后"x"之前串的后缀"ab"是相等的。因此 j 就由 6 变成了 3。因此,我们可以得出规律,j值的多少取决于当前字符之前的串的前后缀的相似度
我们把T串各个位置的 j 值的变化定义为一个数组next,那么next的长度就是T 串的长度。于是我们可以得到下面的函数定义:

next数组值推导

 

KMP模式匹配算法实现

 

跟着这个算法逻辑溜一遍是没问题的,这个算法的发明者简直牛逼!

 

KMP算法仅当模式与主串之间存在许多"部分匹配"的情况下才体现出它的优势,否则两者差异并不明显。 

KMP模式匹配算法改进

若T串的第二、三、四、五位置的字符都与首位的"a"相等,那么可以用首位 next[1] 的值去取代与它相等的字符后续 next[j] 的值。

 

nextval数组值推导 

总结改进过的KMP算法,它是在计算出next值的同时,如果a位字符与它 next 值指向的b位字符相等,则该a位的nextval就指向b位的nextval值,如果不等,则该a位的nextval值就是它自己a位的next的值。 

7. 总结

串(string)是由零个或多个字符组成的有限序列,又名叫字符串。本质上,它是一种线性表的扩展,但相对于线性表关注一个个元素来说,对串这种结构更多的是关注它子串的应用问题,如查找、替换等操作。

现在的高级语言都有针对串的函数可以调用。我们在使用这些函数的时候,同时也应该要理解它当中的原理,以便于在碰到复杂的问题时,可以更加灵活的使用,比如KMP模式匹配算法的学习,就是更有效地去理解index函数当中的实现细节。

这个算法好难🤯

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值