当前位置: 首页 > news >正文

2023王道考研数据结构笔记第四章串

第四章 串

4.1 串的定义

4.1.1 串的相关概念

  1. 串:即字符串(String)是由零个或多个字符组成的有限序列。一般记为S=‘a1a2…an’ (n>=0)

    其中S是串名,单引号(注:有的地方用双引号,如Java、C,有的地方用单引号,如Python)括起来的字符序列是串的值;ai可以是字母、数字或其他字符。

  2. 串的长度:串中字符的个数 n,n = 0 时的串称为空串(用∅\emptyset表示)。

  3. 子串:串中任意个连续的字符组成的子序列。

  4. 主串:包含子串的串。

  5. 字符在主串中的位置:字符在串中的序号。(注意:位序从1开始而不是从0开始)

  6. 子串在主串中的位置:子串的第一个字符在主串中的位置 。

  7. 空串 vs 空格串 M=‘’ M是空串 N=’ ’ N是由三个空格字符组成的字符串,每个空格字符占1B

  8. 串 vs 线性表

    ① 串是一种特殊的线性表,数据元素之间呈线性关系

    ② 串的数据对象限定为字符集(如中文字符、英文字符、数字字符、标点字符等)

    ③ 串的基本操作,如增删改查等通常以字串为操作对象

4.1.2 串的基本操作

  1. StrAssign(&T, chars):赋值操作。把串 T 赋值为 chars。
  2. StrCopy(&T, S):复制操作。由串 S 复制得到串 T。
  3. StrEmpty(S):判空操作。若 S 为空串,则返回 TRUE,否则返回 FALSE。
  4. StrLength(S):求串长。返回串 S 中元素的个数。
  5. ClearString(&S):清空操作。将 S 清为空串。
  6. DestroyString(&S):销毁串。将串 S 销毁(回收存储空间)。
  7. Concat(&T, S1, S2):串联接。用 T 返回由 S1 和 S2 联接而成的新串 。
  8. SubString(&Sub, S, pos, len):求子串。用 Sub 返回串 S 的第 pos 个字符起长度为 len 的子串。
  9. Index(S, T):定位操作。若主串 S 中存在与串 T 值相同的子串,则返回它在主串 S 中第一次出现的位置;否则函数值为 0。
  10. StrCompare(S, T):比较操作。若 S>T,则返回值>0;若 S=T,则返回值=0;若 S<T,则返回值<0。

4.1.3 串的存储结构

1、静态数组实现(定长顺序存储)
#define MAXLEN 255     //预定义最大串长为255
typedef struct {char ch[MAXLEN];    // 每个分量存储一个字符int length;         // 串的实际长度
} SString;
2、动态数组实现(堆分配存储)
typedef struct {char *ch;       // 按串长分配存储区,ch指向串的基地址int length;     // 串的长度
} HString;
HString S;
S.ch=(char *)malloc(MAXLEN*sizeof(char));  //用完需要手动free
S.length=0;

在这里插入图片描述

3、块链存储表示

默认情况下存储密度低,每个节点都只能存储一个字符

解决方法:一个结点存储多个字符

在这里插入图片描述

typedef struct StringNode{char ch;  //存储密度低,每个字符1B,每个指针4Bstruct StringNode * next;
}StringNode,* String;typedef struct StringNode{char ch[4];struct StringNode *next;
}StringNode,* String;      //存储密度提高

4.2 串的模式匹配

串的模式匹配:在主串中找到与模式串相同的子串,并返回其所在位置。

4.2.1 简单的模式匹配算法

思想:将主串中与模式串长度相同的字串拿出来,挨个与模式串对比

当子串与模式串某个对应字符不匹配时,就立即放弃当前子串,转而检索下一个子串

一个示例:

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0yXK4hyr-1677904184313)(数据结构.assets/03d26afdd9a945d38b8e203366f3d634.png)]

分析:

简单模式匹配算法的最坏时间复杂度是O(nm),即每个子串都要对比到最后一个字符,如下面这种情况:

  • 主串:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
  • 子串:1 1 1 1 1 1 1 1 2

其中,n和m分别是主串和模式串的长度。

最好的情况(对于每个子串都只需对比一次):

  • 匹配成功:O(m)
  • 匹配失败:O(n-m+1)=O(n-m)≈O(n)

4.2.2 KMP算法

朴素模式匹配算法的缺点:当某些子串与模式串能部分匹配时,主串的扫描指针i经常回溯,导致时间开销增加。

要了解子串的结构,首先需要了解以下几个概念:前缀、后缀和部分匹配值。

前缀:除了最后一个字符外,字符串的所有头部子串

后缀:除了第一个字符外,字符串的所有尾部子串

‘ab’的前缀是{a},后缀是{b},{a}∩{b}=∅,最长相等前后缀长度为0

'aba’的前缀为{a, ab},后缀为{a, ba}, {a, ab }∩{a, ba}={a),最长相等前后缀长度为1。

'abab '的前缀{a, ab,aba}∩后缀{b, ab, bab }={ab},最长相等前后缀长度为2。

'ababa '的前缀{a, ab,aba, abab }∩后缀{a , ba, aba, baba }={a, aba},公共元素有两个,最长相等前后缀长度为3。

故字符串’ababa’的部分匹配值为00123

接下来详解一下上面这个例子:

由上述方法求子串’abcac’的部分匹配值:

'ab’的前缀{a},后缀{b} {a}∩{b} = ∅

'abc’的前缀{a,ab}, 后缀{c, bc} {a,ab}∩{c, bc} = ∅

'abca’的前缀{a,ab,abc},后缀{a,ca,bca} {a,ab,abc}∩{a,ca,bca} = {a}

'abcac’的前缀{a,ab,abc,abca},后缀{c,ac,cac,bcac} {a,ab,abc}∩{c,ac,cac,bcac} = ∅

将其部分匹配值写成数组形式,就得到了部分匹配值(PM)的表:

编号12345
Sabcac
PM00010

接下来可以使用PM表来进行字符串匹配,其过程如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yp1IyodJ-1677904184313)(数据结构.assets/947517b937b04b7fa0c887b04eda7806.png)]

KMP算法的原理

当c与b不匹配时,已匹配’abca’的前缀a和后缀a为最长公共元素。已知前缀a与b、c均不同,与后缀a相同,故无须比较,直接将子串移动“已匹配的字符数–对应的部分匹配值”,用子串前缀后面的元素与主串匹配失败的元素开始比较即可。

在这里插入图片描述

对算法的改进

已知:右移位数=已匹配的字符数-对应的部分匹配值。写成:
Move=(j−1)−PM[j−1]Move=(j-1)-PM[j-1] Move=(j1)PM[j1]
现在这种情况下,我们在匹配失败时,需要去查找它前一个元素的部分匹配值,这样使用起来有点不方便,故我们可以将PM表右移一位,这样哪个元素匹配失败,则直接看它自己的部分匹配值即可。

将上例的PM表右移一位,则得到了next数组

编号12345
Sabcac
next-10001

我们注意到:

1)第一个元素右移以后空缺的用-1来填充,因为若是第一个元素匹配失败,则需要将子串向右移动一位,而不需要计算子串移动的位数。
2)最后一个元素在右移的过程中溢出,因为原来的子串中,最后一个元素的部分匹配值是其下一个元素使用的,但显然已没有下一个元素,故可以舍去

这样,上式就改写为:
Move=(j−1)−next[j]Move=(j-1)-next[j] Move=(j1)next[j]
就相当于将子串的比较指针回退到:
j=j−Move=j−((j−1)−next[j])=next[j]+1j=j-Move=j-((j-1)-next[j])=next[j]+1 j=jMove=j((j1)next[j])=next[j]+1
但为了让公式更加简洁,我们将next数组整体加1

next数组也可以写成:

编号12345
Sabcac
next01112

最终子串指针变化公式为:
j=next[j]j=next[j] j=next[j]

在实际匹配过程中,子串在内存里是不会移动的,而是指针在变化,书中画图举例只是为了让问题描述得更加形象。next[j]的含义是:在子串的第j个字符与主串发生失配时,则跳到子串的next[j]位置重新与主串当前位置进行比较。

【重要】求next数组,根据如下示例来学习:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BbvJ23vz-1677904184314)(数据结构.assets/a90ce7d2ecbc4b13b4554658845e9167.png)]

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

KMP算法的进一步优化

问题的产生:

在这里插入图片描述

所以引入了nextval数组,对KMP算法进行进一步优化。

故我们在模式串中,当前模式串p和对应的next数组p_next的模式串值相等时,继续查找对应p_next模式串的next数组对应的模式串,直到模式串对应的值不相等。

以下是匹配过程:

在这里插入图片描述

相关文章:

2023王道考研数据结构笔记第四章串

第四章 串 4.1 串的定义 4.1.1 串的相关概念 串&#xff1a;即字符串&#xff08;String&#xff09;是由零个或多个字符组成的有限序列。一般记为S‘a1a2…an’ (n>0) 其中S是串名&#xff0c;单引号&#xff08;注&#xff1a;有的地方用双引号&#xff0c;如Java、C&am…...

【AI绘图学习笔记】深度学习相关数学原理总结(持续更新)

如题&#xff0c;这是一篇深度学习相关数学原理总结文&#xff0c;由于深度学习中涉及到较多的概率论知识&#xff08;包括随机过程&#xff0c;信息论&#xff0c;概率与统计啥啥啥的)&#xff0c;而笔者概率知识储备属实不行&#xff0c;因此特意开一章来总结&#xff08;大部…...

CSGO服务器配置全贴纸插件方法教程

CSGO服务器配置全贴纸插件方法教程 关于插件的警告 一定要了解V社对于CSGO社区服务器的规定&#xff0c;全皮肤插件/全手套插件等&#xff0c;在设置了GSLT的情况下&#xff0c;是有可能被封禁GSLT账号的&#xff08;所以慎用&#xff09; 配置好服务器之后呢&#xff0c;想安…...

Python爬虫——使用socket模块进行图片下载

Python爬虫——使用socket模块进行图片下载什么是socket爬虫的工作流程socket爬取图片为什么能用socket能下载图片socket下载图片和request下载图片的区别使用socket下载一张图片使用socket下载多张图片方法1方法2什么是socket Socket 是一种通信机制&#xff0c;用于实现网络…...

通用游戏地图解决方案设计解析

前言&#xff1a; 在软件开发过程中&#xff0c;我们都希望能设计出一个稳健的&#xff0c;可维护的系统&#xff0c;为了实现这个目的&#xff0c;人们总结出了很多相关的设计原则&#xff0c;比如SOLID原则&#xff0c; KISS原则等等。SOLID每个字母代表了一种设计原则&…...

java @Autowired @Resource @Inject 三个注解的区别

javax.annotation.Resourcejdk 内置的&#xff0c;JSR-250 中的注解。依赖注入通过 org.springframework.context.annotation.CommonAnnotationBeanPostProcessor 来处理。org.springframework.beans.factory.annotation.Autowired org.springframework.beans.factory.annotati…...

「媒体分流直播」媒体直播和传统直播的区别,以及媒体直播的特点

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好直播毋庸置疑已经融入到了我们生活的方方面面&#xff0c;小到才艺&#xff0c;游戏&#xff0c;大到政策的发布&#xff0c;许多企业和机构也越来越重视直播&#xff0c;那么一场活动怎么最大化的进行传播&#xff0c;一是…...

数据是如何在计算机中存储的

我们普通人对于数据存储的认识恐怕大多数都是从自己使用的电脑来的。现在几乎人手一台电脑,而我们的电脑存储着各种各样的文件,比如视频文件、音频文件和Word文档等。这些文件从计算机术语的角度都可以称为数据。 如图1-1所示是Windows 10 “我的电脑”的截图。通过该截图我…...

Day907.分区表 -MySQL实战

分区表 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于分区表的内容。 经常被问到这样一个问题&#xff1a; 分区表有什么问题&#xff0c;为什么公司规范不让使用分区表呢&#xff1f; 一、分区表是什么&#xff1f; 为了说明分区表的组织形式&#xff0c;先创建…...

C++概览:工具链、基础知识、进阶及总结

本篇写给C初学者&#xff0c;作为概览&#xff0c;文中仅包含各方面基础知识&#xff0c;无深入分析。 C基础概念简介 C编译过程示意图 关键词&#xff1a;源文件、预编译、编译、汇编、链接 C工具链总结 cmake项目工程文件是一种中介工程文件&#xff0c;可以转化成其他…...

目标检测中回归损失函数(L1Loss,L2Loss,Smooth L1Loss,IOU,GIOU,DIOU,CIOU,EIOU,αIOU ,SIOU)

文章目录L-norm Loss 系列L1 LossL2 LossSmooth L1 LossIOU系列IOU &#xff08;2016&#xff09;GIOU &#xff08;2019&#xff09;DIOU &#xff08;2020&#xff09;CIOU &#xff08;2020&#xff09;EIOU &#xff08;2022&#xff09;αIOU (2021)SIOU &#xff08;2022…...

JOSN数据转换和解析

文章目录JOSN数据转换和解析内容回顾Map 集合转成 JSON 字符串List 集合转换成 JSON 字符串Ajax 异步和同步异步概念同步概念异步和同步区别异步请求案例同步请求时间格式化旧时间 api 格式化格式化和解析的工具类JSTL 时间格式化JSTL 使用JOSN数据转换和解析 内容回顾 ajax …...

浅析Linux内核中进程完全公平CFS调度

一、前序 目前Linux支持三种进程调度策略&#xff0c;分别是SCHED_FIFO 、 SCHED_RR和SCHED_NORMAL&#xff1b;而Linux支持两种类型的进程&#xff0c;实时进程和普通进程。实时进程可以采用SCHED_FIFO 和SCHED_RR调度策略&#xff1b;普通进程则采用SCHED_NORMAL调度策略。从…...

安装 RustDesk 服务器 (适用 Rocky Linux, CentOS, RHEL 系列发行版)

环境&#xff1a;Rocky Linux 9.1 1. 安装 Docker Engine 可以参考 [[linux-docker-rocky-install]] https://cc01cc.com/2023/03/02/linux-docker-rocky-install/英文可以参考官方文档 Install Docker Engine on RHEL https://docs.docker.com/engine/install/rhel/ 2. 安装…...

23种设计模式-策略模式

策略模式是一种设计模式&#xff0c;它允许在运行时选择算法的行为。它定义了算法家族&#xff0c;分别封装起来&#xff0c;让它们之间可以互相替换&#xff0c;此模式让算法的变化独立于使用算法的客户端。在本文中&#xff0c;我们将深入探讨策略模式的概念和实际应用&#…...

C#开发的OpenRA的游戏主界面怎么样创建

通过前面加载界面布局数据,可以把整个界面逻辑的数据加载到内存, 但是这些数据怎么显示出来,又是没有定义的。比如前面定义了多个界面的布局, 又是怎么样知道需要显示哪一个界面? 现在就来解决这个问题,其实整个游戏都是可以通过yaml文件进行配置的, 所以我们需要从yaml…...

考研还是工作?两战失败老道有话说

老道入职第一周自我介绍谈谈考研谈谈工作新的启程自我介绍 大家好&#xff01;在下是一枚考研失败两次的自认为聪明能干的有点小帅的实则超级垃圾的三非名校毕业的自动化渣男。大一下就加入实验室&#xff0c;在实验室焊板子、画板子、培训、打比赛外加摸鱼&#xff1b;参加过…...

引用是否有地址的讨论的

说在前头&#xff0c;纯属个人理解&#xff0c;关于引用是否有地址&#xff0c;实际上并没有一个很统一的说法&#xff0c; C标准没有规定一个引用是否需要占用一块内存。 这里引用知乎“C 中引用是一块内存的标记&#xff0c;那引用本身有地址吗_百度知道 (baidu.com)”里面的…...

1、JAVA 开发环境搭建 - JDK 的安装配置

文章目录一、下载 JDK81、官网地址&#xff1a;[**https://www.oracle.com**](https://www.oracle.com)二、安装 JDK1、鼠标右键安装包&#xff0c;以管理员身份运行(无脑下一步即可)2、细节说明三、配置环境变量1、为啥要配置环境变量呢&#xff1f;2、原因分析3、配置环境变量…...

【Storm】【六】Storm 集成 Redis 详解

Storm 集成 Redis 详解 一、简介二、集成案例三、storm-redis 实现原理四、自定义RedisBolt实现词频统计一、简介 Storm-Redis 提供了 Storm 与 Redis 的集成支持&#xff0c;你只需要引入对应的依赖即可使用&#xff1a; <dependency><groupId>org.apache.storm…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...