数据结构第3章 串

名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪)
本篇笔记整理:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊)

目录

    • 0、思维导图
    • 1、基本概念
      • 1)主串
      • 2)子串
      • 3)空串
      • 4)串长
    • 2、存储结构
      • 1)顺序存储
      • 2)链式存储
    • 3、模式匹配算法
      • 1)简单模式匹配
      • 2)KMP算法
      • 3)KMP算法改进

0、思维导图

在这里插入图片描述

1、基本概念

1)主串

  • 包含子串的串,即一个完整的字符串

    例如:“数据结构"是一个主串,它包含了"数”、“据”、“结”、"构"等子串。

2)子串

  • 串中任意个连续的字符组成的子序列,即一个字符串的一部分

    例如:“数据结构"的子串有"数”、“据”、“结”、“构”、“数据”、"结构"等。
    “abcd"的子串有"a”、“b”、“c”、"d"等。

3)空串

  • 无任何字符组成的串

    空串的长度为零,用""表示。例如,""是一个空串

4)串长

  • 串中字符的个数

    为一个非负整数,用n表示。例如,"abcd"的串长为4。

2、存储结构

1)顺序存储

顺序存储结构使用一段连续的存储单元一次存放串中的字符。这种结构类似于数组的存储方式,每个字符占用一个存储单元。
在这里插入图片描述

在串的顺序存储结构中,有两种常见的实现方式:定长顺序存储和块分配存储。这两种方式都是在连续的存储单元中存放字符串,但它们在管理这些存储单元的方式上有所不同。

1️⃣定长顺序存储

typedef struct SString
{char ch[N];int length;
}SString;

在定长顺序存储中,每个字符串都被分配一个固定大小的存储区域。这个固定大小通常是根据应用场景中字符串的最大长度来设定的。

  • 优点

    • 存取简单快捷,可以直接通过索引访问任何一个字符
    • 存储结构固定,便于管理。
  • 缺点

    • 不够灵活。如果分配的存储空间大于实际需要,会造成存储空间的浪费;如果小于实际需要,则无法存放更长的字符串。
    • 调整字符串长度时(如拼接、截断操作),可能需要复制整个字符串到新的存储区域,效率较低

2️⃣块分配存储

typedef struct Hstring
{char *ch;int length;
}Hstring;

块分配存储(也称为堆分配存储)中,字符串被存储在动态分配的内存块中。每个字符串可以根据需要分配合适大小的存储空间。

  • 优点

    • 灵活高效地利用内存。仅根据字符串的实际长度分配存储空间,避免了空间浪费
    • 易于处理长度变化较大的字符串操作,如拼接、修改等。
  • 缺点

    • 存储管理相对复杂。需要动态分配和释放内存,可能导致内存碎片。
    • 相较于定长存储,访问字符时可能略微慢一些,因为可能涉及到指针跳转。

3️⃣区别

  • 定长顺序存储适用于字符串长度固定或变化不大的应用场景,如固定长度的记录处理。
  • 块分配存储则适用于字符串长度变化较大的场景,特别是那些需要频繁进行字符串拼接、截断等操作的应用。

2)链式存储

链式存储结构通过一系列的节点来存储串中的字符,每个节点包含一个字符和指向下一个节点的指针。这种结构类似于链表。

3、模式匹配算法

1)简单模式匹配

简单模式匹配算法(也称为朴素模式匹配算法或暴力模式匹配算法)是一种最基本的字符串搜索方法,它尝试在主字符串(通常表示为 S S S)中查找一个子串(称为模式串,表示为 P P P),并返回模式串在主字符串中的位置。

1️⃣算法步骤

  1. 初始化:令主字符串的位置索引为 i = 0 i=0 i=0,模式串的位置索引为 j = 0 j=0 j=0
  2. 匹配:比较主字符串的第 i i i 个字符和模式串的第 j j j 个字符。
    • 如果相等, i i i j j j 同时加一,继续比较下一个字符。
    • 如果不相等,将 i i i 回溯到上一次匹配开始的下一个字符位置,即 i = i − j + 1 i = i - j + 1 i=ij+1,并将 j j j 重置为 0 0 0,重新开始匹配。
  3. 重复:重复步骤2,直到模式串完全匹配,或主字符串的字符比较完毕。
  4. 返回结果:如果模式串 P P P 在主字符串 S S S 中完全匹配,返回模式串开始匹配的位置;否则,返回 − 1 -1 1 或其他表示不匹配的值。

2️⃣举例

假设我们有主字符串 S = "ABCDABCD" S = \text{"ABCDABCD"} S="ABCDABCD" 和模式串 P = "ABC" P = \text{"ABC"} P="ABC"

  • 第一次比较 S [ 0 … 2 ] S[0\ldots2] S[02] P [ 0 … 2 ] P[0\ldots2] P[02],匹配成功。
  • 如果我们寻找下一个匹配,当 S [ 1 … 3 ] S[1\ldots3] S[13] P [ 0 … 2 ] P[0\ldots2] P[02] 不匹配时, i i i 会回溯到 2 2 2(即 1 − 0 + 1 1 - 0 + 1 10+1), j j j 重置为 0 0 0,然后继续匹配。

2)KMP算法

1️⃣概念

KMP算法(Knuth-Morris-Pratt字符串搜索算法),是一种高效的字符串匹配算法。它在不匹配时,通过已匹配的部分信息避免从头开始搜索,从而提高匹配效率。KMP算法的核心构建一个部分匹配表(也称为"失败函数"或"前缀函数"),用以在字符串匹配过程中跳过不必要的比较。

部分匹配表的构建基于以下概念:

  • 前缀:对于字符串 S S S S S S 的前缀是从 S S S 的开头开始的任何子字符串。
  • 后缀:对于字符串 S S S S S S 的后缀是从 S S S 的结尾结束的任何子字符串。

部分匹配表为每个位置 i i i 计算一个值,该值表示字符串从头开始到位置 i i i 的子字符串中,有多长的相同前缀和后缀。这个值被用于当字符不匹配时,确定下一步匹配的起始位置。

2️⃣举例
例如,对于字符串 “ABCDABD”,其部分匹配表如下:

索引0123456
字符ABCDABD
0000120

在实际的字符串搜索过程中,KMP算法使用这个表来决定在不匹配时下一步应该跳过多少个字符。这样,算法避免了从主字符串的每个字符开始匹配,显著提高了搜索效率。

3️⃣补充(PM和next数组求解步骤)

①部分匹配值表(PM)

②next数组求解步骤

  • a.写出PM表

  • b.将PM表值整体右移一位,首位补-1

    • 若题目所给序列是0开始,则此时得到的序列就是next数组

    • 若是从1开始的,则需要整体+1

3)KMP算法改进

nextval数组求解步骤

  • a.nextval[1]=0

  • b.若当前位字符与next数组所对应的字符相比较

    • 如果相等则为nextval数组所对应的next的值

    • 即:nextval[j] = nextval[next[j]]

    • 如果不相等则为next数组所对应的值

    • 即:nextval[j]=next[]j

  • c.具体步骤如下:

    • 1.先将next[j]数组对应的模式串写出来,如果next[j] = 1,那么就写对应j = 1的模式串字符,其余同理

    • 2.写出next[j]数组对应的模式串后,将其与j的模式串字符相比较,如果两者不相等,则nextval[j] = next [j]

    • 3.如果两者相等,则nextval[j]的值等于next[j]的值对应j下的nextval的值,例如next[j] = 1,对应的j = 1,j=1下的nextval值等于0,则nextval[j] = nextval[1] = 0。(也就是nextval[j] = nextval[next[j]])
      在这里插入图片描述

C语言实现KMP算法求解next数组和nextval数组:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
using namespace std;void computeLPSArray(char* pat, int M, int* lps) {int len = 0;lps[0] = 0;int i = 1;while (i < M) {if (pat[i] == pat[len]) {len++;lps[i] = len;i++;} else {if (len != 0) {len = lps[len - 1];} else {lps[i] = 0;i++;}}}
}void computeNextValArray(char* pat, int M, int* lps, int* nextval) {nextval[0] = -1;for (int i = 1; i < M; i++) {int j = lps[i - 1];while (j >= 0 && pat[i] != pat[j]) {j = nextval[j];}nextval[i] = j + 1;}
}void printArray(int* arr, int size, string name) {cout<<name<<":"<<endl;for (int i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}void KMPSearch(char* pat, char* txt) {int M = strlen(pat);int N = strlen(txt);int* lps = (int*)malloc(M * sizeof(int));int* nextval = (int*)malloc(M * sizeof(int));computeLPSArray(pat, M, lps);computeNextValArray(pat, M, lps, nextval);// 打印lps (next数组) 和 nextval数组printArray(lps, M, "Next");printArray(nextval, M, "NextVal");int i = 0;int j = 0;while (i < N) {if (pat[j] == txt[i]) {j++;i++;}if (j == M) {printf("模式匹配索引所在位置: %d \n", i - j);j = lps[j - 1];} else if (i < N && pat[j] != txt[i]) {if (j != 0) {j = nextval[j]; // 使用nextval优化跳转} else {i = i + 1;}}}free(lps);free(nextval);
}int main() {char txt[] = "ABABDABACDABABCABAB";char pat[] = "ABABCABAB";KMPSearch(pat, txt);return 0;
}

在这里插入图片描述

上述内容笔记部分图片来源网络,侵删。
参考内容:
1.《王道数据结构》
2.计算next和nextVal值
3.数据结构电子讲义

Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder)
点赞加关注,收藏不迷路!本篇文章对你有帮助的话,还请多多点赞支持!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/694139.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue3 element-plus 省市区选择器组件封装

文章目录 前言一、省市区数据源处理二、AreaSelect省市区选择器组件封装三 、页面使用 前言 vue3封装一个省市区选择器组件&#xff0c;通过element-plus Cascader 级联选择器实现&#xff0c;效果如下&#xff1a; 一、省市区数据源处理 data.js var areaList {province_…

Unity NavMesh 清除不可行走区域

通常场景中物体设置为static或Navigation Static后&#xff0c;打开Navigation使用默认设置烘焙NavMesh&#xff0c;模型顶部和底部会出现蓝色网格&#xff0c;但其中有部分属于不可能到达区域&#xff0c;如下图 本文介绍两种可去掉NavMesh中不需要网格的方法&#xff1a; 方…

idm下载路径在哪 idm下载保存路径怎么设置 IDM下载器 internetdownloadmanager官方版下载 网络加速器

春节&#xff08;Spring Festival&#xff09;&#xff0c;是中国最隆重最富有特色的传统节日之一。春节期间我们与一家人团聚在一起&#xff0c;其乐融融。2024年春晚已经接近尾声了&#xff0c;很多人已经踏上了返程的路上。在部分地区&#xff0c;如春晚直播过程中或者网络高…

Java学习小记——设计模式

设计模式 设计模式简介Singleton模式Singleton模式简介Singleton的创建双重锁模式Double checked locking作为Java类的静态变量 变继承关系为组合关系组合模式装饰器模式 如何创建对象抽象工厂模式 设计模式简介 设计模式&#xff08;Design pattern&#xff09;代表了最佳的实…

css实现梯形

<div class"trapezoid"></div> .trapezoid {width: 200px;height: 0;border-bottom: 100px solid red; /* 定义梯形的底边 */border-left: 50px solid transparent; /* 定义梯形的左边 */border-right: 50px solid transparent; /* 定义梯形的右边 */} …

初识AXI总线

AXI是一种总线类型&#xff0c;具有高传输速率&#xff0c;高带宽&#xff0c;低时延等特性 AXI具有三种类型&#xff1a; 1.AXI_FULL:满足高性能内存映射&#xff08;memory-mapped&#xff09;需求 2.AXI_lite:不可突发传输 3.AXI_stream:面向数据流的传输 AXI的工作方式&a…

连续字母长度 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 给定一个字符串&#xff0c;只包含大写字母&#xff0c;求在包含同一字母的子串中&#xff0c;长度第 k 长的子串的长度&#xff0c;相同字母只取最长的那个子串。…

【C++】初始化列表、static成员、友元、匿名对象、附练习题

文章目录 前言一、构造函数【初始化列表】1.1 构造函数体赋值1.2 初始化列表1.3 explicit关键字 二、static成员2.1 概念2.2 特性 三、友元3.1 友元函数3.2 内部类 四、匿名对象4.1 拷贝对象时的一些编译器优化 五、再次理解类和对象六、练习题6.1 求123...n&#xff0c;要求不…

Apipost多host服务配置如何使用

最近Apipost新增同环境下多host服务的配置功能&#xff0c;本篇文章带来该功能的使用场景及使用方法。 配置方法&#xff1a; 点击右上角眼睛标识进入环境管理 点击添加服务&#xff0c;输入服务名和URL 配置完成后需要在接口目录中选择该目录下需要使用的host服务&#xff0…

搭建SVN服务端和客户端

参考博客&#xff1a; https://zhuanlan.zhihu.com/p/428552058 先下载这两个文件&#xff1a; 链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1_1v_jKm3h7ZDSYEsgYyovA?pwd11ku 提取码&#xff1a;11ku –来自百度网盘超级会员V5的分享 第一个压缩包里有客户端…

[AIGC] JVM内存结构

JVM内存结构 Java虚拟机&#xff08;JVM&#xff09;内存结构是Java内存管理的基础&#xff0c;并且与JVM的运行机制紧密相关。下面是一个JVM内存结构的示意图&#xff1a; JVM内存主要包括以下几个部分&#xff1a; 方法区&#xff08;Method Area&#xff09; 方法区也被称…

计算机网络-广域通信网

1.广域网概念和分类 什么是广域网&#xff1f; 广域网是指长距离跨地区的各种局域网、计算机、终端互联在一起&#xff0c;组成一个资源共享的通信网络。 广域网分为传统广域网和现代广域网。 传 统 广 域 网公共交换电话网PSTN公共数据网X.25帧中继网FR综合业务数据网ISDN…

docker容器常见操作

目录 一、认识容器 1.1、docker用到的内核技术 1.2、namespace 1.3、Control Group 1.4、LXC与docker区别 二、docker环境准备 2.1、安装docker 2.2、docker daemon环境管理 三、镜像、容器和仓库 3.1、镜像常见操作 3.2、配置镜像加速器 命名空间 3.3、非官方镜像仓…

绩效域-错题笔记

1、虚荣指标&#xff1a;对决策没有帮助的度量指标一般属于虚荣指标。 例如&#xff1a;新访问者的数量比网站的页面访问量更加有用。 2、完工偏差(VAC)用于预测预算赤字或盈余金额&#xff0c;它表示为完工预算(BAC)和完工估算(EAC)之差。 3、完工尚需绩效指数(TCPI)用于估…

【服务器】服务器推荐

一、引言 在数字世界的浪潮中&#xff0c;服务器作为数据存储和处理的基石&#xff0c;其重要性不言而喻。而在这个繁星点点的市场中&#xff0c;雨云以其独特的优势和超高的性价比&#xff0c;逐渐成为众多企业和个人的首选。今天&#xff0c;就让我带你走进雨云的世界&#…

QT day2 2.21

1.使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 代码&#xff1a; #include "mywidget.h" #include "ui_mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(pa…

Open3D0.18.0使用教程

目录 写在前面准备Open3D使用demo编译demo运行demo相关说明 参考完 写在前面 1、本文内容 Open3D在0.15版之后&#xff0c;提供编译好的包&#xff0c;本文是以最新版(截止202402&#xff0c;0.18.0)为例的Open3D使用教程&#xff1b; Open3D其他版本的编译和使用相关教程&…

【安卓基础2】简单控件

&#x1f3c6;作者简介&#xff1a;|康有为| &#xff0c;大四在读&#xff0c;目前在小米安卓实习&#xff0c;毕业入职。 &#x1f3c6;安卓学习资料推荐&#xff1a; 视频&#xff1a;b站搜动脑学院 视频链接 &#xff08;他们的视频后面一部分没再更新&#xff0c;看看前面…

你好,iLogtail 2.0!

作者&#xff1a;张浩翔&#xff08;笃敏&#xff09; 概述 随着可观测数据采集需求的不断推陈出新&#xff0c;多样化的数据输入输出选项、个性化的数据处理能力组合、以及高性能的数据处理吞吐能力已经成为顶流可观测数据采集器的必备条件。然而&#xff0c;由于历史原因&a…

基于RHEL8部署Zabbix6.0,监控不再困难!

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…