【数据结构】数组和字符串(十四):字符串匹配1:朴素的模式匹配算法(StringMatching)

news2025/1/18 11:55:50

文章目录

  • 4.3 字符串
    • 4.3.1 字符串的定义与存储
    • 4.3.2 字符串的基本操作
    • 4.3.3 模式匹配算法
      • 1. 算法原理
      • 2. ADL语言
      • 3. 伪代码
      • 4. C语言实现
      • 5 时间复杂度

4.3 字符串

  字符串(String)是由零个或多个字符(char)顺序排列组成的有限序列,简称为串。例如 “good morning”就是由12个字符构成的一个字符串。一般把字符串记作:

S = ′ ′ a 0 a 1 … a n − 1 ′ ′ S=''a_{0} a_{1}…a_{n-1}'' S=′′a0a1an1′′

  其中S是串名,引号中的字符序列是串值。字符个数是串的长度,长度为0的串被称为空串,因为它不包含任何字符。需要注意的是,空格字符(" ")并不是空串,因为它包含一个字符——空格。
  若把某个串称为主串,则主串中任意个连续的字符组成的子序列被称为子串。子串在主串中第一次出现时,其首字符在主串中的序号被称为该子串在主串中的位置。
  关于字符串的基础知识亦可参考前文:
【重拾C语言】六、批量数据组织(三)数组初值;字符串、字符数组、字符串数组;类型定义 typedef
【重拾C语言】七、指针(三)指针与字符串(字符串与字符串数组;指针与字符串的遍历、拷贝、比较;反转字符串

4.3.1 字符串的定义与存储

  字符串在许多非数值计算问题中扮演着重要的角色,并在模式匹配、程序编译和数据处理等领域得到广泛应用。在高级程序设计语言中,字符串通常被定义为以特殊字符’\0’(称为空字符或字符串结束符)结尾的字符序列。这个约定使得在处理字符串时可以方便地确定字符串的结束位置。关于字符串的存储方式,主要有两种常见的方式:

  • 顺序存储:字符串的字符按照顺序依次存储在连续的内存空间中。这种方式使得字符串的访问和操作效率较高,可以通过索引直接访问任意位置的字符。在顺序存储方式中,字符串的长度可以通过计算字符个数或者遇到’\0’结束符来确定。

  • 链式存储:字符串的字符通过链表的方式进行存储。每个节点包含一个字符和指向下一个节点的指针。链式存储方式可以动态地分配内存,适用于长度可变的字符串。但是相比于顺序存储,链式存储方式需要更多的内存空间,并且访问字符需要遍历链表。

  选择何种存储方式取决于具体的应用场景和需求。顺序存储适合于需要频繁访问和操作字符串的情况,而链式存储适合于长度可变的字符串或者对内存空间要求较高的情况。具体C语言实现可参照前文:
  【数据结构】数组和字符串(十一):字符串的定义与存储(顺序存储、链式存储及其C语言实现)

4.3.2 字符串的基本操作

顺序存储:【数据结构】数组和字符串(十二):顺序存储字符串的基本操作(串长统计、查找、复制、插入、删除、串拼接)
链式存储:【数据结构】数组和字符串(十三):链式字符串的基本操作(串长统计、查找、复制、插入、删除、串拼接)

4.3.3 模式匹配算法

  文本编辑器中常用的“查找”、“替换”和“全部替换”等基本的编辑操作就是最普通的模式匹配问题,即:在文本文件中查找串。它的查找过程可简单描述如下:给定两个字符串变量 S 和 P,其中目标串 S 有n个字符,模式串P有m个字符,m≤n . 从S的给定位置(通常为S的第一个字符)开始,搜索模式串P,如果找到,返回模式串P在S中匹配成功的起始位置;如果没找到(即S中没有P),则返回–1 .
  字符串匹配可以采用多种算法,包括朴素模式匹配算法、KMP(Knuth-Morris-Pratt)算法、Boyer-Moore算法等。这些算法的性能和效率各不相同,具体选择取决于应用的需求和文本数据的规模。

1. 算法原理

  • 从S的字符 S 0 S_{0} S0开始,将P(长度为m)中的字符依次与S中的字符进行比较:
    • S 0 = P 0 , S 1 = P 1 , … , S m − 1 = P m − 1 S_{0}=P_{0},S_{1}=P_{1},…,S_{m-1}=P_{m-1} S0=P0S1=P1Sm1=Pm1则匹配成功,返回与 P 0 P_{0} P0相匹配的字符 S 0 S_{0} S0 S S S中的位置(下标为0);
    • 若某一步, S i ≠ P i S_{i}≠P_{i} Si=Pi,说明此次匹配不成功,以下比较无需进行。
  • 于是再从 S S S的字符 S 1 S_{1} S1开始进行第二次匹配,重复刚才的步骤
    • 看是否有 S 1 = P 0 , S 2 = P 1 , … , S m = P m − 1 S_{1}=P_{0},S_{2}=P_{1},…,S_{m}=P_{m-1} S1=P0S2=P1Sm=Pm1 若匹配成功,返回与P0相匹配的字符S1在S中的下标1.
    • 否则从S的字符S2开始进行第三次匹配’
  • ……
  • 若第 n − m + 1 n-m+1 nm+1次匹配(即最后一次匹配)仍得不到 S n − m = P 0 , S n − m + 1 = P 1 , … , S n − 1 = P m − 1 S_{n-m}=P_{0},S_{n-m+1}=P_{1},…,S_{n-1}=P_{m-1} Snm=P0Snm+1=P1Sn1=Pm1,说明匹配失败,返回 -1 .
  • 这种模式匹配算法被称为朴素的模式匹配算法

2. ADL语言

在这里插入图片描述

3. 伪代码

function naivePatternMatching(S, P):
    n = length(S)  # 目标串的长度
    m = length(P)  # 模式串的长度

    for i from 0 to n - m:
        j = 0
        while j < m and S[i + j] == P[j]:
            j = j + 1

        if j == m:  # 如果模式串完全匹配
            return i  # 返回匹配位置

    return -1  # 未找到匹配

# 示例用法
S = "ABABCABAB"
P = "ABAB"
result = naivePatternMatching(S, P)
if result != -1:
    print("模式串在目标串中的位置:", result)
else:
    print("未找到匹配")

4. C语言实现

#include <stdio.h>
#include <string.h>

int naivePatternMatching(const char* S, const char* P) {
    int n = strlen(S);  // 目标串的长度
    int m = strlen(P);  // 模式串的长度

    for (int i = 0; i <= n - m; i++) {
        int j = 0;
        while (j < m && S[i + j] == P[j]) {
            j++;
        }

        if (j == m) {  // 如果模式串完全匹配
            return i;  // 返回匹配位置
        }
    }

    return -1;  // 未找到匹配
}

int main() {
    const char* S = "QomolangmaH";
    const char* P = "lang";
//    const char* P = "gan";

    int result = naivePatternMatching(S, P);
    if (result != -1) {
        printf("模式串在目标串中的位置: %d\n", result);
    } else {
        printf("未找到匹配\n");
    }

    return 0;
}

在这里插入图片描述

在这里插入图片描述

5 时间复杂度

  朴素模式匹配算法的优点是过程简单,缺点是效率低。在最坏情况下,该算法要匹配n-m+1次,每次匹配要做m次比较,因此最坏情况下的比较次数是m×(n-m+1),时间复杂性为O(m×(n-m+1)),通常情况下,m的值远小于n的值,于是最坏情况下的时间复杂性可粗略地记为O(n×m)。对于长文本和模式串,可能会导致性能问题。因此,有更高效的模式匹配算法,如KMPBoyer-Moore等,用于更快速地找到匹配位置,具体内容详见后文。

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

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

相关文章

共焦显微镜使用

x.1 细胞培养 x.2 样品制备 以细菌为例&#xff0c;我们使用荧光染色细菌&#xff0c;静置15分钟。 15分钟后我们使用实验室的专用培养皿&#xff0c;选择吸收100uL的溶液滴在在培养皿中心。 x.3 显微镜使用 我们按照1, 2, 3, 4的顺序打开显微镜&#xff0c; 打开电脑&…

降级python

起因&#xff1a; python版本过高不能下载一个包&#xff0c;需要降级 首先使用 python --version 查看python版本 然后conda install python3.10 python3.10会下载到这个目录下&#xff08;这个千万别找错&#xff09; 然后更换路径 alias python/home/zky/.conda/envs/c…

【MAC+IP】以太网帧格式

图片出自&#xff1a;https://info.support.huawei.com/info-finder/encyclopedia/zh/MTU.html

FFmpeg 硬件加速视频转码指南

基于 Windows 下演示&#xff0c;Linux 下也可以适用。 所使用 ffmpeg 版本为 BtbN 编译的 win64-gpl 版&#xff08;非 gpl-share&#xff09;&#xff0c;项目地址&#xff1a;BtbN / FFmpeg-Builds 也可以使用 gyan.dev 编译的 git-full 版&#xff0c;地址&#xff1a;gyan…

053基于web+springboot的宠物咖啡馆平台的设计与实现

欢迎大家关注&#xff0c;一起好好学习&#xff0c;天天向上 文章目录 一项目简介技术介绍 二、功能组成三、效果图四、 文章目录 一项目简介 本基于Spring Boot的宠物咖啡馆平台的设计与实现有管理员和用户以及看护师三个角色。用户功能有个人中心&#xff0c;咖啡菜品管理&a…

微信视频号直播间引流粉丝脚本软件实操教学,文章加视频演示详细教学方法

我是小刘&#xff0c;第一我要讲的是为什么要做视频号&#xff1f; 今天我们来去演示的是视频号直播间引流脚本的一个教学&#xff0c;我这边用文章加视频讲解的方法来分享给大家。关于引流有两点&#xff0c;1 就是自媒体推广&#xff0c;2就是脚本引流&#xff0c;我今天给大…

定时任务场景下的代码审查:continue和return的滥用可能引发潜在bug

文章目录 前言for 循环中的continue&#xff0c;break和return实际业务中的滥用总结写在最后 前言 在最近的代码审查中&#xff0c;有帮忙审查了组里一个刚毕业1年不到的应届生&#xff0c;发现他写的其中一段代码将for循环中的break、continue、return滥用&#xff0c;导致了…

口碑超好高质量经典小说,收获无数赞誉,完结多年还是热门之作

经典好文&#xff0c;小郑来为您推荐五本值得一读的好书&#xff0c;这些书籍不仅可以让您的时间不再无聊&#xff0c;还能让您在阅读中获得更多的知识和乐趣。 《传说管理局》 这本书的世界观严谨且庞大&#xff0c;充满了科幻和玄幻元素。如果您喜欢科幻和玄幻类型的书籍&am…

力扣:149. 直线上最多的点数(Python3)

题目&#xff1a; 给你一个数组 points &#xff0c;其中 points[i] [xi, yi] 表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱…

记一次heapdump泄漏获取服务器权限

文章目录 一、漏洞原因二、漏洞利用三、漏洞进一步利用1、工具下载2、通过关键字查询3、通过配置redis的默认账号和密码进行登录4、添加定时计划任务,进行反弹shell5、成功获取服务器的shell补充四、总结五、免责声明一、漏洞原因 扫描目录发现某个spring框架存在大量泄露信息…

DBeaver关闭代码的提示

在DBeaver中会遇到如下现象&#xff0c;很烦&#xff0c;怎么取消这个提示框呢&#xff1f; 解决方案&#xff1a;

第二章 02Java基础-数据类型、标识符、键盘录入

文章目录 前言一、数据类型二、标识符三、键盘录入总结前言 今天我们学习Java基础,数据类型、标识符、键盘录入 一、数据类型 1.数据类型大体上可以分为两类,一类是基本数据类型,另外一类是引用数据类型。今天我们学习基本数据类型。 2.基本数据类型可以分为四类八种,整…

一看就懂,原来这就是计算机网络

引言 计算机网络&#xff0c;听上去很专业的样子&#xff0c;其实我们可以换种思维来理解。 正文 什么是计算机网络&#xff1f; 下图就是计算机网络&#xff0c;所有能联网的设备连接在一起就组成了互联网 计算机网络有什么用&#xff1f; 计算机网络的作用就是用于设备之…

VueX mapState、mapGetters、mapActions和mapMutaions 的使用

一、mapState和mapGetters 如果我们想要读取VueX中的State数据的Getters数据时&#xff0c;需要使用$store.state.数据名 和 $store.getters.数据名。 当我们State和getters中的数据多了以后&#xff0c;书写会很麻烦&#xff1a; 如果我们想要使用方便可以配置计算属性来简化…

Arduino设置SoftwareSerial缓冲区大小

SoftwareSerial的缓冲区大小设置 概述修改缓冲区的大小实验 概述 新的Arduino的ESP8266软串口的缓冲区原来老的库中有宏定义可以用来修改接收和发送缓冲区的大小。在现在新的库中已经没有这个设置了&#xff0c;那怎么才能修改缓冲区的大小哪&#xff1f; 修改缓冲区的大小 …

5.2用队列实现栈(LC225-E)

算法&#xff1a; 其实这道题不用像上一道题一样&#xff0c;用两个队列实现栈。 由于队列的数据结构特性。用一个队列就可实现栈。 难点还是在出队的时候&#xff1a; 比如队列[1,2,3]&#xff0c;要模拟一个栈入栈就是直接append&#xff08;其实就是C中的push&#xff0…

creating server tcp listening socket 127.0.0.1:6379: bind No error

window下启动redis服务报错&#xff1a; creating server tcp listening socket 127.0.0.1:6379: bind No error 解决方案如下按顺序输入如下命令即可连接成功 redis-cli.exeshutdownexit运行&#xff1a;redis-server.exe redis.windows.conf shutdown出现以下错误&#xff…

数据结构之队的实现

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

变压器那些事

电磁感应 电磁感应效应是指当一个导体或线圈处于变化的磁场中时&#xff0c;会在导体或线圈中产生感应电动势或感应电流的现象。 根据法拉第电磁感应定律&#xff0c;当一个导体或线圈被置于变化的磁场中时&#xff0c;通过该导体或线圈的磁通量会发生变化&#xff0c;从而在…

零代码复现-TCGA联合GEO免疫基因结合代谢基因生信套路(一)

经过一段时间的积累&#xff0c;搭建的分析平台已经日渐进入稳定的状态&#xff0c;很多粉丝也在和我们反馈&#xff0c;让我们出一下零代码生信套路课。 小编找了很久&#xff0c;发现某某机构出的TCGA联合GEO 免疫基因代谢基因的生信套路&#xff0c;该套路应用常见相对来说…