【数据结构】串的模式匹配:简单的模式匹配算法,KMP算法

news2024/9/24 18:03:00

 欢~迎~光~临~^_^

目录

知识树

1、什么是串的模式匹配 

2、简单的模式匹配算法

3、KMP算法

3.1 算法原理

3.2 C语言实现KMP算法 

3.3 求next数组

3.4 KMP算法优化(对next数组的优化) 


知识树

 

1、什么是串的模式匹配 

        串的模式匹配是在一个字符串中查找另一个较小的字符串(称为模式)的过程。模式匹配的目的是在文本串中查找一个或多个匹配字符串。这种搜索可以使用各种算法进行,包括暴力算法,KMP算法和Boyer-Moore算法等。模式匹配广泛应用于文本编辑器、搜索引擎、计算机网络和计算机安全等领域。

2、简单的模式匹配算法

        这个算法的时间复杂度是O(mn),其中m是模式串的长度,n是文本串的长度。在最坏情况下,即文本串中的每个字符都匹配模式串中的每个字符,时间复杂度为O(m(n-m+1)),因此朴素模式匹配算法在处理大型文本串时可能会变得很慢。

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

int naive_search(const char text[], const char pattern[]) {
    int text_len = strlen(text);
    int pattern_len = strlen(pattern);
    for (int i = 0; i <= text_len - pattern_len; i++) {
        int j;
        for (j = 0; j < pattern_len; j++) {
            if (text[i + j] != pattern[j])
                break;
        }
        if (j == pattern_len)
            return i;
    }
    return -1;
}

int main() {
    char text[] = "ABABCABCABABABD";
    char pattern[] = "ABABD";
    int pos = naive_search(text, pattern);
    if (pos >= 0)
        printf("Pattern found at position %d in the text.", pos);
    else
        printf("Pattern not found in the text.");
    return 0;
}
 

3、KMP算法

3.1 算法原理

        KMP算法是一种字符串匹配算法,它的原理是利用已知的信息尽可能减少匹配次数。KMP算法的核心是一个跳转表格,也称为Next数组或失配函数。

        在匹配的过程中,当发现不匹配的情况时,KMP算法会利用跳转表格中已经计算好的信息,直接跳过部分不需要匹配的字符,从而减少匹配次数。具体来说,KMP算法会根据当前匹配的位置和已知的信息,计算出下一个字符需要匹配的位置,从而避免了不必要的匹配操作。

        KMP算法的时间复杂度为O(m+n),其中m和n分别为模式串和文本串的长度,求next数组时间复杂度O(m);模式匹配过程最坏时间复杂度O(n)。相比于朴素的字符串匹配算法,KMP算法在匹配效率和性能上有了很大的提高。

3.2 C语言实现KMP算法 

        下述代码中,next()函数用于计算模式串的next数组,kmp()函数用于在文本串中查找模式串。在main()函数中,首先输入文本串和模式串,然后调用next()函数生成模式串的next数组,最后调用kmp()函数在文本串中查找模式串。若模式串存在于文本串中,输出模式串在文本串中的位置,否则输出不存在的信息。

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

void next(char *pattern, int *next_arr) {
    int i = 0, j = -1;
    next_arr[0] = -1;
    int len = strlen(pattern);
    while (i < len - 1) {
        if (j == -1 || pattern[i] == pattern[j]) {
            i++;
            j++;
            next_arr[i] = j;
        } else {
            j = next_arr[j];
        }
    }
}

int kmp(char *text, char *pattern, int *next_arr) {
    int i = 0, j = 0;
    int text_len = strlen(text), pattern_len = strlen(pattern);
    while (i < text_len && j < pattern_len) {
        if (j == -1 || text[i] == pattern[j]) {
            i++;
            j++;
        } else {
            j = next_arr[j];
        }
    }
    if (j == pattern_len) {
        return i - j;
    } else {
        return -1;
    }
}

int main() {
    char text[100], pattern[100];
    int next_arr[100];

    printf("请输入文本串:");
    gets(text);
    printf("请输入模式串:");
    gets(pattern);

    next(pattern, next_arr);
    int index = kmp(text, pattern, next_arr);
    if (index != -1) {
        printf("模式串在文本串中的位置是:%d\n", index);
    } else {
        printf("文本串中不存在模式串!\n");
    }

    return 0;
}
 

3.3 求next数组

        next(j)的含义是:在子串的第j个字符与主串发生失配时,则跳到子串的next(j)位置重新与主串当前位置进行比较。
        next(1)都无脑写0;next(2)都无脑写1;
        其他next:在不匹配的位置前,划一根分界线,模式串一步一步往后退,直到分界线之前“能对上”,或模式串完全跨过分界线为止,此时 j 指向哪,next数组值就是多少。

void next(char *pattern, int *next_arr) {
    int i = 0, j = -1;
    next_arr[0] = -1;
    int len = strlen(pattern);
    while (i < len - 1) {
        if (j == -1 || pattern[i] == pattern[j]) {
            i++;
            j++;
            next_arr[i] = j;
        } else {
            j = next_arr[j];
        }
    }
}
 

        在上述代码中,pattern表示模式串,next_arr表示next数组。首先将next_arr[0]置为-1,i表示当前已匹配的字符数,初始值为0,j表示当前已匹配的字符中,能和下一位字符匹配的最长前缀的末尾位置,初始值为-1。在循环中,若第i个字符能和第j+1个字符匹配,则更新next_arr[i+1]=j+1,否则将j更新为next_arr[j],重复此过程直到结束。

例1,若模式串为ABCDABD,则next数组为[-1, 0, 0, 0, 0, 1, 2, 0]

例2,下面是"ababaaababaa"模式串对应的next数组值:

- a b a b a a a b a b a a
- 0 0 1 2 3 4 5 2 3 4 5 6

因此,"ababaaababaa"模式串的next数组值为[0, 0, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6]。

next数组的生成过程是KMP算法的核心部分,它可以大大提高模式匹配的效率。

3.4 KMP算法优化(对next数组的优化) 

                KMP算法优化:可以采用KMP算法的优化手段,通过推导next[j]和nextval[next[j]]的关系,减少计算次数。

//核心代码
nextval[1]=0;  
for(int j = 2;j < pattern.length;j++)
{
    if(pattern[next[j]] == pattern[j])
        nextval[j] = nextval[next[j]];
    else
        nextval[i] = nextval[j];
}

🤞❤️🤞❤️🤞❤️串的模式匹配的知识点总结就到这里啦,如果对博文还满意的话,劳烦各位看官动动“发财的小手”留下您对博文的赞和对博主的关注吧🤞❤️🤞❤️🤞❤️

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

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

相关文章

NSA SELinux将在Linux 6.6中去品牌化为SELinux

导读安全增强型 Linux (Security-Enhanced Linux&#xff0c;SELinux) 是一个 Linux 内核模块&#xff0c;也是 Linux 的一个安全子系统&#xff1b;提供了一个实施访问控制安全策略的安全模块&#xff0c;现在已被广泛用于增强生产型 Linux 服务器和其他系统的安全性。 安全增…

ChatGPT 或其它 AI,能用在文书创作上吗?

新的申请季已经正式开始&#xff0c;一些热门项目的ED截止日期也不再遥远&#xff0c;因此很多准留学生们都已经开始了关于文书的创作。 而随着科技的不断发展&#xff0c;以ChatGPT为首的一众AI工具也作为一种辅助手段愈发融入了我们的生活。 那么不免就会有一些同学在准备申…

基于springboot实现“闲一品”交易平台电商系统项目【项目源码+论文说明】

基于springboot实现“闲一品”交易平台电商系统项目 摘要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;闲一品交易平台当然也不能排除在外。闲一品交易平台是以实际运用为开…

redis的基础底层篇 zset的详解

一 zset的作用以及结构 1.1 zset作用 redis的zset是一个有序的集合&#xff0c;和普通集合set非常相似&#xff0c;是一个没有重复元素的字符串集合。常用作排行榜等功能&#xff0c;以用户 id 为 value&#xff0c;关注时间或者分数作为 score 进行排序。 1.2 zset的底层结…

【计算机网络】Tcp详解

文章目录 前言Tcp协议段格式TCP的可靠性面向字节流应答机制超时重传流量控制滑动窗口&#xff08;重要&#xff09;拥塞控制延迟应答捎带应答标志位具体标志位三次握手四次挥手粘包问题TCP异常情况listen的第二个参数 前言 前面我们学习了传输层协议Udp&#xff0c;今天我们一…

春秋云镜 CVE-2013-2134

春秋云镜 CVE-2013-2134 S2-015 靶标介绍 2.3.14.3 之前的 Apache Struts 2 允许远程攻击者通过标记在通配符匹配期间未正确处理的所提出的操作名称的请求执行任何 OGNL 代码&#xff0c;这是与 CVE-2013-2135 不同的漏洞。 启动场景 漏洞利用 工具利用 得到flag flag{b92…

.360勒索病毒和.halo勒索病毒数据恢复|金蝶、用友、ERP等数据恢复

导言&#xff1a; 随着数字化时代的持续发展&#xff0c;网络安全威胁也变得前所未有地复杂和难以应对。在这个充满挑战的网络环境中&#xff0c;勒索病毒已经成为了一种极为危险和破坏性的威胁。最近引起广泛关注的是.360勒索病毒&#xff0c;一种可怕的恶意软件&#xff0c;…

基于深度学习的加密恶意流量检测

加密恶意流量检测 研究目标定位数据收集数据处理基于特征分类算法的数据预处理基于源数据分类算法的数据预处理 特征提取模型选择基于数据特征的深度学习检测算法基于特征自学习的深度学习检测算法 训练和评估精确性指标实时性指标 应用检验改进 摘录自&#xff1a;Mingfang ZH…

如何实现 pdf 转 word

前言&#xff1a;最直接的方式 wps 充会员可以直接转&#xff0c;但是单纯为了 使用这个功能有没啥必要 pdf转word方法 在线转换wps转换其他收费转换方式 在线转换 介绍在线转换&#xff0c;虽然样式简陋但是可以转换成功&#xff0c;转换以后也没有失真 http://ssyr.mynatap…

#循循渐进学51单片机#步进电机与蜂鸣器#not.8

1、能够理解清楚单片机IO口的结构。 2)t1相当于PnP三级管&#xff0c;t2相当于npn三极管 3&#xff09; 强推挽io具有较强的驱动能力&#xff0c;电流输出能力很强。 2、能够看懂上下拉电阻的电路应用&#xff0c;并且熟练使用上下拉电阻。 3、理解28BYJ-48减速步进电机的工作…

Android 官方屏幕适配之ScreenMatch

背景&#xff1a; Android 项目的一个app需要适配手机平板&#xff0c;为了一套UI和可以适配2个不同屏幕&#xff0c;记录一个适配的技巧&#xff1a; 前提&#xff0c;使用这个框架&#xff1a;GitHub - wildma/ScreenAdaptation: :fire:一种非常好用的 Android 屏幕适配——…

#循循渐进学51单片机#c语言基础和流水灯实现#not.3

1、熟练掌握二进制、十进制和十六进制的转换方法。 多少进制就是多少之间相加&#xff0c;比如十六进制就是十六一次一加&#xff1b;二进制转化十六进制&#xff0c;分成四个一组。 2、C语言变量类型与取值范围&#xff0c;for、while等基本语句的用法。 for、while等基本语句…

基于Y向连贯性算法的多边形扫描线生成(适用于凸多边形和凹多边形)【原理+java实现】

问题介绍 给定一个多边形&#xff0c;可能是凸多边形&#xff0c;也可能是凹多边形&#xff0c;现需要生成一系列线条将多边形描述出来&#xff0c;示例如下图 原始方法 遇到这个问题&#xff0c;大家首先想到的方法可能是&#xff1a;使用一系列的竖线来和多边形进行相交&…

Java入坑之语法糖

一、for和for-each 1.1for和for-each概念 for 循环是一种常用的循环结构&#xff0c;它可以通过一个变量&#xff08;通常是 i&#xff09;来控制循环的次数和范围。for 循环的语法格式如下&#xff1a; for (初始化; 布尔表达式; 更新) {//代码语句 }for-each 循环是 Java …

数据库系统的三级模式和二级映射

数据库系统的三级模式结构基本概念模式&#xff08;schema&#xff09;外模式&#xff08;external schema&#xff09;内模式 (Internal Schema&#xff09; 数据库系统的二级映射外模式/模式映象模式/内模式映象 总结感谢 &#x1f496; 数据库系统的三级模式结构 数据库系统…

Web安全与攻防

Web安全概述 在Internet大众化及Web技术飞速演变的今天&#xff0c;在线安全所面临的挑战日益严峻。伴随着在线信息和服务的可用性的提升&#xff0c;以及基于Web的攻击和破坏的增长&#xff0c;安全风险达到了前所未有的高度。Web安全可以从以下三个方面进行考虑&#xff1a;…

Matlab图像处理-从RGB转换为HSV

从RGB转换为HSV HSV彩色系统基于圆柱坐标系。从RGB转换为HSV需要开发将(笛卡儿坐标系中的)RGB值映射到圆柱坐标系的公式。多数计算机图形学教材中已详细推导了这一公式&#xff0c;故此处从略。 从RGB转换为HSV的MATLAB函数是rgb2hsv&#xff0c;其语法为&#xff1a; hsv_imag…

商业综合体AI+视频安防监控与智能监管解决方案

一、方案背景 商业综合体需要具备更好的品质和环境才能吸引更多客流&#xff0c;如何有效地进行内部管理、外部引流&#xff0c;是综合体管理人员思考的重点。 传统的视频监控需要靠人盯牢屏幕或者发生报警后通过查看录像&#xff0c;才能找到意外事件相关人员与起因&#xf…

VMware启用共享文件夹

1. 启用 编辑虚拟机设置 - 选项 - 共享文件夹 - 总是启用 - 添加 2. 启动Ubuntu查看 正常情况/mnt目录会出现文件夹hgfs 如果不存在&#xff0c;可参考 这篇文章 操作 如果安装VMWare tools后/mnt中有hgfs但没共享文件&#xff0c;可参考 这篇文章 如果出现 mount: unkno…

Mac 安装软件各种报错解决方案

Mac 安装软件各种报错解决方案 文章目录 Mac 安装软件各种报错解决方案一. 打开允许“允许任何来源”二. 无法打开"xxx"&#xff0c;因为它不是从App Store下载三. 无法打开"xxx"&#xff0c;因为 Apple无法检查其是否包含恶意软件。四. "xxx"已…