数据结构 4 串、数组和线性表
本文最后更新于:2023年12月24日 晚上
b站王卓老师课程学习
P67待补充
4.1 串
串(string):由零个或多个字符组成的有限序列
所谓序列说明串的相邻字符之间具有前驱和后继关系
子串:一个串中任意个连续字符组成的子序列(含空串)称为该串的子串。
例如,"abcde’的子串有:““、”a“、”ab“、“abcd” 和 “abcde” 等
真子串是指不包含自身的所有子串。
主串:包含子串的串相应地称为主串
字符位置:字符在序列中的序号为该字符在串中的位置、
子串位置:子串第一个字符在主串中的位置
空格串:由一个或多个空格组成的串,与空串不同,空格串:“ ”
,空串:“”
a在d中的位置:5
串相等:当且仅当两个串的长度相等并且各个对应位置上的字符都相同时,这两个串才是相等的
所有空串都是相等的
4.2 案例引入
之后有一个字符串的经典问题,字符串的匹配
4.3 串的类型定义、存储结构、算法
4.3.1 串的抽象数据类型的定义
4.3.2 串的存储结构
串中元素逻辑关系与线性表的相同,串可以采用与线性表相同的存储结构。
串的逻辑结构与线性表相似,区别仅在于串的数据对象约束为字符集
串的基本操作和线性表的差别:在线性表的操作中,多以“单个元素”作为操作对象,在串的操作中,多以“串的整体”作为对象
1. 定长顺序存储结构
固定长度的顺序表来存储字符串。
这种用的最多
我们知道,顺序表通常使用数组来实现,数组的创建方式有两种,分别是静态数组和动态数组。以 C 语言为例,静态数组指的就是长度固定的数组,动态数组指的是调用 malloc() 函数创建的数组,例如:
1 |
|
对于定义好的静态数组,它的长度是无法修改的;动态数组则不同,它的长度是可变的,定义后还可以调用 realloc() 函数扩容。
串的定长顺序存储既然用固定长度的顺序表来实现,就限定了只能用静态数组实现,不能用动态数组。
🍧🍧🍧其实就是说这里的定长顺序存储结构是静态数组实现,第二种方法堆分配存储结构是动态数组实现
1 |
|
1 |
|
这里解释一下上面的
initSString
函数:
void initSString(SString *s, const char *str) {}
- SString *s:这是一个指向
SString
结构体的指针,表示函数将会修改传递给它的SString
对象。- const char *str:这是一个指向常量字符的指针,表示函数将会接受一个 C 字符串作为参数,这个 C 字符串是以
'\0'
结尾的。
s->length = strlen(str);
:
strlen(str)
返回输入字符串str
的长度,不包括结尾的空字符 ('\0'
)。s->length
被赋值为字符串的长度,即存储在SString
结构体中的length
成员。
strncpy(s->ch + 1, str, MAXLEN);
:
strncpy
函数用于复制字符串。它接受三个参数:目标字符串、源字符串和要复制的最大字符数。s->ch + 1
是目标字符串的起始位置,表示从数组ch
的索引 1 开始复制,因为这里假设字符串从索引 1 开始。str
是源字符串。MAXLEN
是要复制的最大字符数。- 这行代码的作用是将源字符串的内容复制到
SString
结构体的ch
成员中,从索引 1 开始,最多复制MAXLEN
个字符。
s->ch[s->length + 1] = '\0';
:
- 这行代码在字符串的末尾添加了一个空字符
'\0'
,以确保字符串正确终止。s->length
是字符串的长度,所以s->length + 1
是字符串的下一个位置,用于放置空字符。总体而言,
initSString
函数的作用是接受一个常规的 C 字符串(以'\0'
结尾),计算其长度并将其复制到自定义的字符串结构体SString
中。这个函数假设字符串是从索引 1 开始的,并在复制过程中保留了一个空字符作为字符串的结尾。
2. 堆分配存储结构
堆分配存储是指的是用一整块适当大小的堆内存空间来存储字符串。
所谓堆内存,就是堆区的内存空间。以 C 语言为例,程序运行时占用的内存空间会分成很多大小不等的块(区域),它们通常被称为堆区、栈区、常量区、全局数据区、代码区等。这些区域各有分工,比如全局数据区用来存储全局变量和静态变量,代码区用来存储要运行的程序指令等。
和内存的其它区域相比,堆区最大的特点就是:不会自动分配和回收,必须由程序员手动申请,使用完后再手动释放。
在 C 语言中,申请堆内存的操作可以调用 malloc() 或者 calloc() 函数来完成,例如:
1 |
|
如果 malloc() 函数执行成功,我们就申请了能存储 5 个字符的堆内存空间。
如果申请的堆内存空间不够用,还可以调用 realloc() 函数扩容,例如:
1 |
|
realloc() 函数执行成功,原本只能存 5 个字符的堆内存,扩容成能存储 10 个字符。
堆内存使用完后,需要手动调用 free() 函数释放,例如:
1 |
|
强调:堆内存必须及时手动释放,否则会造成内存泄漏。
1 |
|
3. 块链存储表示
串的链式存储结构:
- 优点:操作方便
- 缺点:存储密度较低
\(存储密度=串值所占的存储/实际分配的存储\)
可将多个字符存放在一个结点中,以克服其缺点,这就是串的链式存储结构---块链结构
- 优点:不需要大块连续空间;
- 缺点:占用存储量大,操作复杂,不如顺序存储方式方便
- 块链结点大小≥1
1 |
|
这部分可以再参考一下:串的块链存储结构(C语言)详解 (biancheng.net)
4.3.3 串的模式匹配算法
老师说串的基本操作在c语言里面都学过了,所以就讲了这一个(我学你的内阁😡
算法目的:确定主串中所含子串(模式串)第一次出现的位置 (定位)
算法应用:搜索引擎、拼写检查、语言翻译、数据压缩
算法种类:
- BF算法(Brute-Force,又称古典的、经典的、朴素的、穷举的)
- KMP算法(特点:速度快)
1. BF算法
Brute-Force简称为BF算法,亦称简单匹配算法。采用穷举法的思想
主串:正文串
子串:模式串
算法的思路是从S的每一个字符开始依次与T的字符进行匹配
下图展示了模式串T = “abcac”
和主串S的匹配过程
Index(S,T,pos)
- 将主串的第pos个字符和模式串的第一个字符比较
- 若相等,继续逐个比较后续字符
- 若不等,从主串的下一字符起,重新与模式串的第一个字符比较
- 直到主串的一个连续子串字符序列与模式串相等。返回值为S中与T匹配的子序列第一个字符的序号,即匹配成功。
- 否则,匹配失败,返回值 0
1 |
|
1 |
|
BF算法复杂度分析
2. KMP算法
Knuth Morris Pratt 算法
草,听了半天有点难听懂啊😴😴😴
KMP算法是D.E.Knuth、J.H.Morris和VR.Pratt共同提出的,简称KMP算法
该算法较BF算法有较大改进,从而使算法效率有了某种程度的提高.
好像期末考试不考,之后再来补这个坑😬😬
KMP算法完全攻略(C语言实现) (biancheng.net)
4.4 数组
4.4.1 数组的定义和特点
数组:按一定格式排列起来的具有相同类型的数据元素的集合
一维数组:若线性表中的数据元素为非结构的简单元素,则称为一维数组
一维数组的逻辑结构:线性结构。是一个定长的线性表
声明格式:数据类型变量名称[长度]
例:int num[5] ={0,1,2,3,4};
二维数组
二维数组:若一维数组中的数据元素又是一维数组结构,则称为二维数组
二维数组的逻辑结构:
- 非线性结构:每一个数据元素既在一个行表中又在一个列表中。
- 线性结构:该线性表的每个数据元素也是一个定长的线性表
声明格式:数据类型 变量名称[行数] [列数]
例:int num[5] [8]
,一个五行八列的数组
在C语言中,一个二维数组类型也可以定义为一维数组类型(其分量类型为一维数组类型)
即:typedef elemtype array2[m][n]
等价于:
1 |
|
三维数组:若二维数组中的元素又是一个一维数组, 则称作三维数组
n维数组:若n-1维数组中的元素又是一个一维数组结构则称作n维数组
结论:线性表结构是数组结构的一个特例,而数组结构又是线性表结构的扩展
- 数组特点:结构固定——定义后,维数和维界不再改变。
- 数组基本操作:除了结构的初始化和销毁之外只有取元素和修改元素值的操作
4.4.2 数组的抽象数据类型定义
4.4.3 数组的顺序存储
因为:
数组特点:结构固定维数和维界不变
数组基本操作:初始化、销毁、取元素、修改元素值。一般不做插入和删除操作
所以:
一般都是采用顺序存储结构来表示数组
注意:数组可以是多维的但存储数据元素的内存单元地址是一维的,因此,在存储数组结构之前,需要解决将多维关系映射到一维关系的问题
1. 一维数组
例,有数组定义: int a[5];
2. 二维数组
存储单元是一维结构,而数组是个多维结构,则用一组连续存储单元存放数组的数据元素就有个次序约定问题
- 一个例题
4.4.4 特殊矩阵的压缩存储
矩阵:一个由 m*n个元素排成的 m 行n 列的表
矩阵的常规存储:将矩阵描述为一个二维数组
矩阵的常规存储的特点:可以对其元素进行随机存取;矩阵运算非常简单;存储的密度为 1。
不适宜常规存储的矩阵:值相同的元素很多且呈某种规律分布;零元素多
矩阵的压缩存储:为多个相同的非零元素只分配一个存储空间;对零元素不分配空间。
什么是压缩存储?
若多个数据元素的值都相同,则只分配一个元素值的存储空间,且零元素不占存储空间。
什么样的矩阵能够压缩?
一些特殊矩阵,如:对称矩阵,对角矩阵,三角矩阵,稀疏矩阵等
什么叫稀疏矩阵?
矩阵中非零元素的个数较少 (一般小于5%)
先不边看网课边记笔记了,感觉这个对期末考试用处没直接看题目,然后针对性的学有用——2023.12.29
参考: