算法与数据结构-第五章:串

串的定义:

是由零个或多个字符组成的串 , 又名字符串 。

在英语单词中, 同样有神奇的地方。即使是 lover 也有个 over,即使是 friend 也有个 end ,即使是 believe 也有个 Lie. " 你会发现,本来不相干,甚至对立的两个词,却有某种神奇的联系。这可能是创造这几个单词的那些智者们也投有想到的问题。
 

一般记为 s= "a1a2..… .an" (n>0时 , 其中,s 是串的名称,用双引号(有些书中也用单引号)括起来的字符序列是串的值,注意单引号不属于串的内容。

ai (1<=i<=n)间的 可以是字母 、 数字或其他字符 , i 就是该字符在串中的位置。

串中的字符数目 n 称为串的长度, 定义中谈到"有限"是指长度 n 是一个有限的数值 。

零个字符的串称为空串 (oull string) , 它的长度为零,可以直接用两双引号 "" 表示,也可以用希腊字母 " φ" 来表示。

所谓的序列,说明串的相邻字符之间具有前驱和后继的关系 。
 

还有一些概念需要解释。
空格串,是只包含空格的串。注意它与空串的区别,空格串是有内容有长度的,而且可以不止一个空格。


子串与主串, 串中任意个数的连续字符组成的子序列称为该串的子串,相应地,包含子串的串称为主串。


子串在主串中的位置就是子串的第一个字符在主串中的序号。


开头我所提到的 " over " 、 "end"," lie " 其实可以认为是 、ver" 、 " friend " 、" believe " 这些单词字符串的子串 。
 

串的比较

两个数字 , 很容易比较大小。 2 比 1 大,这完全正确,可是两个字符串如何比较?

比如 "silly" 、 "stupid" 这样的同样表达"愚蠢的"的单词字符串,它们在计算机中的大小其实取决于它们挨个字母的在字符集中的前后顺序。

它们的第一个字母都是 "s" ,我们认为不存在大小差异,而第二个字母,由于 "i" 字母比 "t" 字母要靠前,所以 i < γ ,于是我们说 "silly" < "stupid" 。

事实上 , 串的比较是通过组成串的字符之间的编码来进行的 , 而字符的编码指的是字符在对应字符集中的序号。
计算机中的常用字符是使用标准的 ASCII 编码,更准确一点, 由 7 位二进制数表示一个字符,总共可以表示 128 个字符。

后来发现一些特殊符号的出现, 128 个不够用,于是扩展 ASCII 码由 8 位二进制数表示一个字符,总共可以表示 256 个字符,这已经足够满足以英语为主的语言和特殊符号进行输入、存储、输出等操作的字符需要了。

 

可是,单我们国家就有除汉族外的满、田、藏、蒙古 、 维吾尔等多个少数民族文字,换作全世界估计要有成百上千种语言与文字,显然这 256 个字符是不够的,因此后来就有了 Unicode 编码, 比较常用的是由 16 位的二进制数表示一个字符 ,这样总
共就可以表示 216 个字符,约是 65 万多个字符,足够表示世界上所有语言的所有字符了。

 

当然,为了和 ASCII 码兼容Unicode 的前 256 个字符与 ASCIl 码完全相同。


所以如果我们要在 C 语言中比较两个串是否相等,必须是它们串的长度以及它们各个对应位置的字特都相等时,才算是相等。即给定两个串 s= "a1a2……an" , t="b1b2… … bm" ,当且仅当 n=m ,且 al=bl , a2=b2 ,……, an=bm 时 ,我们认为 s=t 

 

注意在java中如果对字符串使用判断符号实际判断的是引用值(对应c之中的内存地址)。

 

还是那句话在c语言中是直接比较字母在字符集中的顺序大小,而且在c中可以直接使用符号来进行对比,但是在java中必须使用java中的方法来进行对比。

String Str0="asdzc";

String Str1="zzxcv";

str0.compareTo(str1);

 

说一个'字符串比较'的应用。
我们的英语词典 , 通常都是上万个单词的有序排列 。就大小而言,前面的单词比后面的要小你在查找单词的过程,其实就是在比较字符串大小的过程。

 

串的抽象数据类型

串的存储结构

串的顺序存储

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


既然是定长数组,就存在一个预定义的最大串长度, 一般可以将实际的串长度值保存在数组的 0 下标位置3 有的书中也会定义存储在数组的最后一个下标位置。

但也有些编程语言不想这么干,觉得存个数字占1个空间麻烦。

它规定在串值后面加一个不计入串长度的结束标记字符,比如\0。来表示串值的终结,这个时候,你要想知道此时的串长度,就需要遍历计算一下才知道,其实这还是需要占用1个空间。
 

串的顺序存储方式其实是有问题的,因为字符串的操作,比如两串的连接 Concat、新串的插入 Strlnsert , 以及字符串的替换 Replace ,都有可能使得串序列的长度超过了数组的长度 MaxSize,也就是溢出。

 

串的链式存储结构
 

对于串的链式存储结构,与线性表是相似的,但由于串结构的特殊性,结构中的每个元素数据是一个字符,如果也简单的应用链表存储串值, 一个结点对应一个字符,就会存在很大的空间浪费 。

因此,一个结点可以存放一个字符,也可以考虑存放多个字符,最后一个结点若是未被占满时,可以用"#" 或其他非串值字符补全,如图 5-5-3 所示。
 

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


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

朴素的模式匹配算法

子串的定位操作通常称做串的模式匹配, 应该算是串中最重要的操作之一。

其实主要模式是利用子串去历遍主串,类似于暴力破解法。
 

假设我们要从下面的主串 S="goodgoogle"中,找到 T="google"这个子串的位置。我们通常需要下面的步骤。

S为主串,T为子串

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

分析一下 , 最好的情况是什么?那就是一开始就区配成功,比如 "googlegood"中去找 google ,时间复杂度为 0(1) 。 稍差一些,如果像刚才例子中第二、 三、四位一 样,每次都是首字母就不匹配,那么对 T 串的循环就不必进行了,比如" abccdefgoogle" 中去找 "google" 。 那么时间复杂度为 O(n+m) , 其中 n 为主串长度,m 为要匹配的子串长度。根据等概率原则,平均是 (n+m ) /2 次查找,时间复杂度为O(n+m).
 

那么最坏的情况又是什么?就是每次不成功的匹配都发生在串 T 的最后一个字符。

举一个很极端的例子。

主串为 s= "00000000000000000000000000000000000000000000000001 " ,而要匹配的子串为 T= " 0000000001 " ,前者是有 49 个 " 0 " 和1 个 "1" 的主串,后者是 9 个 " 0 " 和 1 个 "1 " 的子串。

在匹配时,每次都得将 τ中字符循环到最后一位才发现,哦,原来它们是不匹配的 。

这样等于 T 串需要在 S 串的前 40 个位置都需要判断 10 次,并得出不匹配的结论,如图 5-6-6 所示。

直到最后第 41 个位置,因为全部匹配相等,所以不需要再继续进行下去 ,如图5-6-7 所示。

如果最终投有可匹配的子串, 比如是 T= "0000000002" ,到了第41位置判断不匹配后同样不需要继续比对下去 。

因此最坏情况的时间复杂度为 O((n - m+ 1)*m)。

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

KMP模式匹配算法

一种跳跃式的算法。

这个算法略微复杂,大家可以在这里看一下,这个是我看过挺多视频讲解里讲的最好的。
https://www.bilibili.com/video/av3246487?from=search&seid=4042661948068252423

其实蛮复杂的。

还没搞清楚就不继续写了,省的误导。

本章笔记到此结束。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值