KMP 算法中 next 数组的构建函数 get_next

news2025/6/6 20:22:10

 KMP 算法中 next 数组的构建函数 get_next ,负责计算模式串的 next 数组,核心是通过递推找到每个位置的 “最长相等前缀后缀长度”。(下标从 1 开始):

一、函数作用

get_next(SString T, int next[]) 的任务:
为模式串 T 生成 next 数组,next[i] 表示 模式串中第 i 个字符失配时,应该回退到的位置(本质是 “前 i-1 个字符的最长相等前缀后缀长度”)。

二、代码逐行解析

void get_next(SString T, int next[]) {
    // 初始化:
    // i:模式串当前处理到的位置(从 1 开始,对应字符 T.ch[1])
    // j:记录当前最长相等前缀后缀的长度(初始为 0,对应“没有前缀”)
    i = 1; 
    j = 0;  
    // next[1] 固定为 0(模式串第一个字符失配时,没有前缀可回退,特殊处理)
    next[1] = 0;  

    // 循环条件:i 遍历模式串的每个字符(直到模式串末尾)
    while (i < T.length) {  
        // 情况 1:j=0(回到起点) 或 当前字符匹配(T.ch[i] == T.ch[j])
        if (j == 0 || T.ch[i] == T.ch[j]) {  
            // i、j 同时后移,扩展匹配长度
            ++i;  
            ++j;  
            // 记录 next[i]:当前最长相等前缀后缀长度是 j
            next[i] = j;  
        } 
        // 情况 2:当前字符不匹配(T.ch[i] != T.ch[j])
        else {  
            // j 回退到 next[j](找更短的前缀后缀继续匹配)
            j = next[j];  
        }
    }
}

三、核心逻辑拆解(结合递推思想)

  1. 初始化

    • i=1 从模式串第二个字符开始(第一个字符 next[1]=0 已固定)。
    • j=0 表示 “当前没有匹配的前缀”。
  2. 循环处理每个字符

    • 匹配时(T.ch[i] == T.ch[j]
      i 和 j 同时后移,next[i] = j 表示 “前 i 个字符的最长相等前缀后缀长度是 j”。
      例:模式串 ababc,当 i=3(字符 a)、j=1(字符 a)匹配时,i++=4j++=2next[4]=2(前 4 个字符 abab 的最长相等前缀后缀是 ab,长度 2)。

    • 失配时(T.ch[i] != T.ch[j]
      j = next[j] 让 j 回退到更短的前缀位置,继续尝试匹配。
      例:模式串 ababc,若 i=5(字符 c)、j=3(字符 a)失配,j = next[3] = 1(回退到更短的前缀),再比较 T.ch[5] 和 T.ch[1]

四、对于i,j可能不见名知意,有点混乱,那下面将它们换掉 ,并再次进行解释

①、重命名变量后的代码(下标从 1 开始)

// 生成模式串 T 的 next 数组
// next[position] 表示:当模式串在 position 位置失配时,应回退到的位置
void get_next(SString T, int next[]) {
    // current_pos:当前处理到模式串的哪个位置(初始从第二个字符开始)
    int current_pos = 1;
    // prefix_len:当前最长相等前缀的长度(初始为 0,表示无前缀)
    int prefix_len = 0;
    // 第一个字符失配时,只能回退到模式串开头(下标 0,实际代码中用 0 表示)
    next[1] = 0;

    // 遍历模式串的每个字符(从第二个开始,直到末尾)
    while (current_pos < T.length) {
        // 情况 1:prefix_len 回退到 0(回到起点),或者当前字符匹配成功
        if (prefix_len == 0 || T.ch[current_pos] == T.ch[prefix_len]) {
            // 继续匹配下一个字符
            current_pos++;
            prefix_len++;
            // 记录:当匹配到 current_pos 位置失配时,应回退到 prefix_len 位置
            next[current_pos] = prefix_len;
        }
        // 情况 2:当前字符匹配失败
        else {
            // 回退 prefix_len 到更短的前缀位置,继续尝试匹配
            prefix_len = next[prefix_len];
        }
    }
}

②、关键变量解释

原变量新变量含义
icurrent_pos当前处理到模式串的哪个位置(对应字符 T.ch[current_pos]
jprefix_len当前最长相等前缀的长度,也表示前缀的下一个待匹配位置(T.ch[prefix_len]
nextnext核心数组,next[pos] 表示模式串在 pos 位置失配时应回退到的位置

③、核心逻辑拆解(带例子)

以模式串 T = "ABABC"(下标从 1 开始)为例,逐步推导 next 数组:

1. 初始化
current_pos = 1;  // 处理第 1 个字符 'A'
prefix_len = 0;   // 无前缀
next[1] = 0;      // 第一个字符失配时,回退到 0(实际逻辑中表示从头开始)
2. 处理 current_pos = 1(字符 A
  • prefix_len = 0 → 进入 if 分支:

    current_pos++;  // 2
    prefix_len++;   // 1
    next[2] = 1;    // 表示:当匹配到第 2 个字符失配时,应回退到第 1 个字符
    
3. 处理 current_pos = 2(字符 B
  • T.ch[2] = 'B'T.ch[1] = 'A' → 不匹配 → 进入 else 分支:

    prefix_len = next[1] = 0;  // 回退到 0
    
  • 再次循环:prefix_len = 0 → 进入 if 分支:

    current_pos++;  // 3
    prefix_len++;   // 1
    next[3] = 1;    // 表示:当匹配到第 3 个字符失配时,应回退到第 1 个字符
    
4. 处理 current_pos = 3(字符 A
  • T.ch[3] = 'A'T.ch[1] = 'A' → 匹配 → 进入 if 分支:

    current_pos++;  // 4
    prefix_len++;   // 2
    next[4] = 2;    // 表示:当匹配到第 4 个字符失配时,应回退到第 2 个字符
    
5. 处理 current_pos = 4(字符 B
  • T.ch[4] = 'B'T.ch[2] = 'B' → 匹配 → 进入 if 分支:

    current_pos++;  // 5
    prefix_len++;   // 3
    next[5] = 3;    // 表示:当匹配到第 5 个字符失配时,应回退到第 3 个字符
    

四、总结

get_next 函数的核心逻辑:

  1. 匹配成功:扩展当前前缀长度,并记录 next 值。
  2. 匹配失败:回退到更短的前缀位置(通过 next 数组),继续尝试匹配。

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

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

相关文章

IDEA 开发PHP配置调试插件XDebug

1、安装PHP环境 为了方便&#xff0c;使用的PhpStudy。 安装路径&#xff1a;D:\resources\phpstudy_pro\Extensions\php\php7.3.4nts 2、下载Xdebug Xdebug: Downloads 选择对应的版本下载&#xff0c;本次使用的是7.3。 3、配置Xdebug 在php.ini中添加Xdebug配置。 D…

奇异值分解(SVD):线性代数在AI大模型中的核心工具

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;10年以上C/C, C#, Java等多种编程语言开发经验&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开…

MySQL——视图 用户管理 语言访问

目录 视图 用户管理 数据库权限 访问 准备工作 使用函数 mysql界面级工具 连接池 视图 这里的视图与事务中的读视图是两个不同的概念&#xff1a;视图是一个虚拟表&#xff0c;其内容由查询定义。同真实的表一样&#xff0c;视图包含一系列带有名称的列和行数据。视图的…

二、Sqoop 详细安装部署教程

作者&#xff1a;IvanCodes 日期&#xff1a;2025年6月2日 专栏&#xff1a;Sqoop教程 Apache Sqoop 是一个强大的工具&#xff0c;用于在 Hadoop (HDFS, Hive, HBase) 与关系型数据库 (如 MySQL, PostgreSQL, Oracle) 之间高效传输数据。本教程将详细指导您如何根据官方网站截…

【C语言预处理详解(下)】--#和##运算符,命名约定,命令行定义 ,#undef,条件编译,头文件的包含,嵌套文件包含,其他预处理指令

目录 五.#和##运算符 5.1--#运算符 5.2--##运算符 六.命名约定&#xff0c;#undef&#xff0c;命令行定义 6.1--命名约定 6.2--#undef 6.3--命名行定义 七.条件编译 常见的条件编译指令&#xff1a; 1.普通的条件编译&#xff1a; 2.多个分支的条件编译(可以利用条…

03.搭建K8S集群

K8S集群搭建的方式 目前主流的搭建k8s集群的方式有kubeadm、minikube、二进制包三种方式&#xff1a; kubeadm&#xff08;本案例搭建方式&#xff09; 是一个工具&#xff0c;用于快速搭建kubernetes集群&#xff0c;目前应该是比较方便和推荐的&#xff0c;简单易用 kubea…

RDMA简介3之四种子协议对比

RDMA协议共有四种子协议&#xff0c;分别为InfiniBand、iWARP、RoCE v1和RoCE v2协议。这四种协议使用统一的RDMA API&#xff0c;但在具体的网络层级实现上有所不同&#xff0c;如图1所示&#xff0c;接下来将分别介绍这四种子协议。 图1 RDMA四种子协议网络层级关系图 Infin…

【最新版】西陆洗车系统源码全开源+uniapp前端+搭建教程

一.系统介绍 一款基于ThinkPHPUniapp开发的多门店洗车系统&#xff0c;包含用户端&#xff08;小程序&#xff09;、门店员工端&#xff08;小程序&#xff09;、门店端&#xff08;PC&#xff09;、平台管理端&#xff08;PC&#xff09;。 门店分连锁门店和独立门店&#xf…

Linux开发工具(apt,vim,gcc)

目录 yum/apt包管理器 Linux编辑器 vim 1.见一见vim 2.vim的多模式 3.命令模式底行模式等 4.vim的配置 Linux编译器 gcc/g 1.预处理&#xff08;宏替换&#xff09; 2.编译&#xff08;生成汇编&#xff09; 3.汇编&#xff08;生成机器可识别代码&#xff09; 4.连…

鸿蒙Next开发真机调试签名申请流程

背景&#xff1a; 在学习鸿蒙next开发应用的初期总是会遇到一堆的问题&#xff0c;毕竟鸿蒙next开发不管是他的ArKTS语言还是他的开发工具DevEco Studio都还在起步阶段&#xff0c;就像当初的Android起步一样&#xff0c;总会有资料不足的一些问题。就比如我们学习下载完DevEco…

[yolov11改进系列]基于yolov11引入上下文锚点注意力CAA的python源码+训练源码

【CAA介绍】 本文记录的是基于CAA注意力模块的RT-DETR目标检测改进方法研究。在远程遥感图像或其他大尺度变化的图像中目标检测任务中&#xff0c;为准确提取其长距离上下文信息&#xff0c;需要解决大目标尺度变化和多样上下文信息时的不足的问题。CAA能够有效捕捉长距离依赖…

【linux】全志Tina预编译一个so库文件到根文件系统/usr/lib/下

一、sdk中新建文件夹 路径&#xff1a; V:\t113\work3\t113\openwrt\package\feeds\libs\md5util md5util为需要注入的库文件夹。 文件结构 libs md5util files libmd5util.so makefile etc.. 二、编写makefile include $(TOPDIR)/rules.mkPKG_NAME : md5util PKG_VERSIO…

C# 类和继承(成员访回修饰符)

成员访回修饰符 本章之前的两节阐述了类的可访问性。对类的可访问性&#xff0c;只有两种修饰符&#xff1a;internal和public。 本节阐述成员的可访问性。类的可访问性描述了类的可见性&#xff1b;成员的可访问性描述了类成员的可 见性。 声明在类中的每个成员对系统的不同…

Linux-文件管理及归档压缩

1.根下的目录作用说明&#xff1a; /&#xff1a;Linux系统中所有的文件都在根下/bin&#xff1a;(二进制命令目录)存放常用的用户命令/boot&#xff1a;系统启动时的引导文件&#xff08;内核的引导配置文件&#xff0c;grub配置文件&#xff0c;内核配置文件&#xff09; 例…

微软认证考试科目众多?该如何选择?

在云计算、人工智能、数据分析等技术快速发展的今天&#xff0c;微软认证&#xff08;Microsoft Certification&#xff09;已成为IT从业者、开发者、数据分析师提升竞争力的重要凭证。但面对众多考试科目&#xff0c;很多人不知道如何选择。本文将详细介绍微软认证的考试方向、…

Dify工作流实践—根据word需求文档编写测试用例到Excel中

前言 这篇文章依赖到的操作可查阅我之前的文章&#xff1a; dify里的大模型是怎么添加进来的&#xff1a;在Windows本地部署Dify详细操作 flask 框架app.route()函数的开发和调用&#xff1a;PythonWeb开发框架—Flask工程创建和app.route使用详解 结构化提示词的编写&…

【LC实战派】小智固件编译

这篇写给立创吴总&#xff0c;是节前答应他配合git代码的说明&#xff1b;也给所有对小智感兴趣的小伙伴。 请多提意见&#xff0c;让这份文档更有价值 - 第一当然是拉取源码 - git clone https://github.com/78/xiaozhi-esp32.git 完成后&#xff0c;先查看固件中实际的…

jdbcTemplate.query备忘录

jdbcTemplate.query中使用全部字符串和参数注入&#xff0c; 查询速度为什么差距这么大 如何正确使用JdbcTemplate参数化查询 1、使用?占位符 String sql "SELECT * FROM users WHERE name LIKE ?"; List<User> users jdbcTemplate.query(sql,new Object[…

如何搭建Z-Blog PHP版本:详细指南

Z-Blog是一款功能强大且易于使用的博客平台&#xff0c;支持PHP和ASP两种环境。本文将重点介绍如何在PHP环境下搭建Z-Blog博客系统&#xff0c;帮助您快速上线自己的个人博客站点。 准备工作 1. 获取Z-Blog PHP版本 首先&#xff0c;访问Z-Blog官方网站下载最新版本的Z-Blog…

Github Copilot新特性:Copilot Spaces-成为某个主题的专家

概述 当今的工程团队都会面临知识碎片化的问题。关键的上下文分散在代码、文档和团队成员的头脑中&#xff0c;这使得他们很难在一个新的领域快速上手并完成工作。Copilot Spaces 通过集中您的项目上下文解决了这个问题&#xff0c;因此 Copilot 可以根据您的工作提供更智能、…