数据结构学习记录:第四章:串

原文章:

数据结构学习记录:第四章:串 - 知乎 (zhihu.com)

此文章为作者本人搬运至该网站。

说在前头:

各位在学习过程中,如果有任何不懂的地方,可以随时评论或者私信我!!!我每天都在高强度网上冲浪(这一点真的属实),从各位进行评论,到我发现评论,我认为应该最多不超过半个小时,所以啊,各位,尽情用你们的评论和私信淹没我吧!(=・ω・=)


在学习串之前,我们一定已经接触过一个名字类似的内容——字符串,以及其的一些用法,

而在这里,看书上那么繁琐而又奇葩的内容,你是不是又被绕晕了?

其实那些内容就是把原来字符串的东西换了个说辞又写了一遍!

现在我把书上的内容过滤掉一遍,再看应该就会清晰许多。


1.串是什么:

这里就不用我讲了吧?目前在我看来,其实就和字符串,也就是字符数组,大同小异罢了,

而我觉得,串里面的许多函数,基本上一半都能用#include <string.h>里面的函数来解决。


2.定长顺序串的表示:

按照课本的内容来说,串有定长顺序存储和堆分配存储,以及块链存储,

而在我对课本翻来翻去,并请教了诸多同学后,发现 定长顺序存储 不仅用处不大,而且课本内容还说得云里雾里,不明所以,

于是在这里我就简单提一下,并说一下为什么我认为课本没讲清楚:

从存储表示我们可以看出,串的定长存储最大为255,而为什么要在前面加个unsigned呢,因为char的数据范围是从-128到+127,如果改成unsigned,那么就成了0到255,可能是为了扩大存储范围吧。

而这个typedef是老朋友了,通过这个可以定义串,就是比如SString T,就相当于char T[255](这个应该大家都知道了罢),

那么怎么表示串的长度的呢?课本是这样描述的:

其中课本用的是第一个,

用S1[0]表示串的长度,

但是!!!

你也没告诉我怎么得出来S1[0]啊???而且S1[0]不应该和后面的数据一样是char类型的吗,为什么还能和define出的int类型的MAXSTRLEN相比较呢???这能出结果吗???

得知这里的内容的时候我是一脸懵b的,

为什么不用string库里面的strlen函数呢?

这里同理,

这里是求S的字串Sub,最后的

Sub[0] = len

一个int类型的数赋值给char类型。。。。。。

所以我认为这里不需要过多计较,

而且重要的是,我看别的博主的关于串的教程,除了那些直接照抄课本的水博客,基本上都没有关于这个S1[0]的内容,所以,直接略过就好~

(帮大家避雷了,不愧是我(叉腰))

3.堆排序存储表示:

现在才是正菜!

这样看的话,其实和之前内容没什么差别,就是指针指向的数组,用malloc动态分配内存。

(1).生成串:

不过这里却不是直接用malloc创建新的串,而是把一个chars指针指向的串赋给了T,这个函数虽然简单,但由于之前没有见过,我还是讲一下吧:

第一个if语句,不用多说,如果这个T有数据,那就释放再创建个新的,

下面这个for循环可就有来头了!仔细看,

for (i = 0, c = chars; *c; ++i, ++c);

这个for循环最后有一个分号!!!

这绝对不是写错了,而是有bear而来(

如果对for循环烂熟于心的话,其实就会了解到,其实第二个分号后面的内容也可以放在for循环大括号内,那么这样就实现了一个独立的for循环,而中间那个*c我个人认为是判断c指向的地方有没有数据,也就相当于

*c != '\0'

而如果是指针的形式,应该也可以写成 c != NULL,

(在这里我要提示一下,NULL只可以用作对指针的判断,不能对数组元素判断(当年的痛))

如果把这个for循环改成while循环,就是这样:

i = 0;
c = chars;
while ( *c != '\0' ){
  i++;
  c++;
}

而后面的内容应该也挺简单的,无非就是分配空间,数据更新之类的,

不过这个。。。。。

T.ch[0...i-1] = chars[0...i-1];

其实是个伪代码,就是把数据一个个传过去,换成c语言就是:

for (int j = 0; j < i; j++){
  T.ch[j] = chars[j];
}

这样子偷懒是吧。。。。。

(2).比较串和清空串:

(3).返回字串:

这些都比较简单,应该自己都能看懂吧~~

如果实在看不懂或者有什么地方有疑问也可以来私信问我~~

4.串的块链存储表示

和线性表的链式存储结构相类似,也可采用链表方式存储串的值,也就是说,每一个串都是链表的节点,如图:

添加图片注释,不超过 140 字(可选)

CNUNKSIZE就是每个节点的串的长度,最后再有个指向下一个节点的指针。

不过毕竟这里不是重点内容(老师连pta作业都没有留串的内容),所以就简单介绍一下。


5.串的模式匹配算法:

接下来更是重量级!!!

串的模式匹配一般用于求字串位置的定位,也就是求字串在主串中的位置(找到主串中某一部分的从头到尾都和字串一模一样且字符连续的),首先用的就是普通匹配算法:

这里还是用的是定长顺序串的模式,下面改成堆排序的方式:

int Index(Htring S, HString T,int pos) {
	// 返回子串T 在主串 S中第 pos个字符之后的位置。若不存在,则函数值为0
	//其中,T非空,1 <= pos <= StrLength(S)。
	i = pos - 1;
	j = 0;
	while(i <= S.length && j <= T.length) {
		if(S.ch[i] == T.ch[j]) {		// 继续比较后继字符
			++i;
			++j;
		} else {
			i = i - j + 1;		//指针后退重新开始匹配
			j = 0;
		}
	}
	if(j > T.length)
		return i - T.length + 1;
	else
		return 0;
}// Index

(i和j都减去了1是因为数组的特性,a[0])这里我们以这个例子来讲:

找到在主串第2(pos)个字符之后字串DEF的位置,这里我把其他字符都简化为同一个字符Z,并且中间加了空格(空格不需要判断),

pos值为2,那么i的值就为1,在主串中就是第二个Z的位置,

(这里的箭头不是指针啊喂!只是个提示)

之后进入while循环,if判断,显然两个不一样,那么就走else,

也许有人对这个指针后退重新匹配,这个i = i - j +1;不是很理解,我们先直接带入,这里i是1,j是0,减完之后,i变成了2,j还是0,也就是说这个指针后退其实是针对j的,

而那个i = i - j +1;我们先按下不表,继续循环,显然这个还是不一样,继续i = i - j +1,

直到这里,再进行判断,两个字符终于相等了!那么就把i和j都前进一格:

E同理:

但是在这里,两个又不一样了!

那么就走else,i = i - j +1,

这里是不是看明白了?

其实else判断的就是直到主串中找到和子串匹配的第一个字符,之后i和j同时自加,如果最后不行的话,那就返回到找到第一个字符的地方,再给i加个1,让i从这个地方再继续往下找和子串匹配的第一个字符,直至全部匹配为止。

这样不断类推,那就实现了定位函数。

在这种情况下,算法的时间复杂度为O(n+m),其中n和m分别为主串和子串的长度(来源课本),

但是在有些情况下,该算法的效率却很低。比如子串为'00000001',而主串为'000000000000000000000000000000000000000000000000000001'(课本上比这个还多。。。。。),

由于子串的前七个字符均为'0',又主串中前52个字符也均为'0',一开始的每一次比较都会在子串的最后一个字符出现不相同,这样才讲指针i回溯到i-6的位置上,并且还要重新比较8次。在整个匹配过程中,指针i一共要回溯45次,一共的while循环次数为46 * 8(index * m)为368次!!!

那么这样,该算法在最坏情况下的时间复杂度为O(n*m),还是挺麻烦的。

而我们也可以看出,有很多地方其实是不需要进行匹配的,

所以下一步,我们带来一个新算法——KMP算法。

6.KMP算法:

。。。

。。。

。。。

崩溃了家人们,我今天从早上看到晚上,还是没看懂。。。。。

这里是我搜索的记录TAT

学习的过程也是极为痛苦,经历了建立认知——发现不对——残忍打破认知体系——重新认知这些痛苦过程

我先放出这些链接,等我回头想起来了再看吧。。。。或者你们也可以看这些内容,反正里面每一篇文章都有人评论说醍醐灌顶。。。

KMP算法详解-CSDN博客

可能是全网最清晰的KMP算法讲解-CSDN博客

史上最详细的KMP算法教程,看这一篇就够了-CSDN博客

从头到尾彻底理解KMP(2014年8月22日版)_kmp算法 csdn-CSDN博客

KMP 算法详解 - 知乎 (zhihu.com)

KMP算法——通俗易懂讲好KMP算法:实例图解分析+详细代码注解 --》你的所有疑惑在本文都能得到解答_kmp算法例子-CSDN博客

【天勤考研】KMP算法易懂版_哔哩哔哩_bilibili

而压垮我想要搞懂kmp算法的最后一根稻草是什么呢。。。

是我同学告诉我这个地方我们老师说过让自己理解!!!

也就是说老师都不想讲!!!

而且我还落下了那么多课,PTA页不布置串的题目,还钻这个kmp算法干什么!!!

所以我就先挖个坑吧。。。。等什么时候有功夫钻研了,或者有高人指点之后我再写吧。。。

下面是我之前尝试写出来的东西,不过也烂尾了,建议先不要看了。。。

此时此刻我的心情

真的很抱歉。。。。

但是如果我的学习效率很高的话,我也不至于去写这系列文章了。。。。。

  • 8
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值