【数据结构】四、串

目录

一、定义

二、表示与实现

定长顺序存储

堆分配存储

链式存储

三、BF算法

四、KMP算法

1.求next数组

方法一

方法二(考试方法)

2.KMP算法实现

方法一

方法二

3.nextval

4.时间复杂度 


本节最重要的就是KMP算法,其他要求不高

一、定义

串类型的定义:串即字符串,是由零个或多个字符组成的有限序列,是数据元素为单个字符的特殊线性表。

串长:串中字符的个数(n≥0),n=0 时称为空串\O \varnothing

空白串:由一个或多个空格符组成的串,空串不等于空白串

子串:串S中任意个连续的字符序列叫S的子串, S叫主串(空串是任意串的子串;任意串S都是S本身的子串,除S本身外,S的其他子串称为S的真子串)

子串位置:子串的第一个字符在主串中的序号

字符位置:字符在串中的序号

串相等:串长度相等,且对应位置上字符相等

下面关于串的的叙述中,哪一个是不正确的?

A. 串是字符的有限序列

B. 空串是由空格构成的串

C. 模式匹配是串的一种重要运算

D. 串既可以采用顺序存储,也可以采用链式存储

答案:B 

二、表示与实现

定长顺序存储

用预先设定好长度的数组存储串。string[MAXSIZE + 1],加一是为了给串尾的‘\0’留空间

堆分配存储

也就是用malloc动态创建数组,还可以用realloc增加空间

链式存储

用链表存储串值,易插入和删除

1.链表结点的数据域长度取1

2.链表结点数据域长度取n(块链结构)

当数据元素较多时,块链结构存储密度更高

三、BF算法

BF算法是一种串的模式匹配算法,目的是确定主串中所含子串第一次出现的位置

思路

主串S,模式串T

将ST的头部对齐,逐个比较字符是否相同

一旦出现不同,将T后移一位,重新从头开始比较

直到完全匹配为止,否则匹配失败

写成代码:

主串S,模式串T【i,j为S,T的指针】

将ST的头部对齐【i,j分别指向S,J的首位】,逐个比较字符是否相同【S[i]==T[j]】

一旦出现不同【S[i] != T[j]】,将T后移一位【i = i - j + 2(回溯)】,重新从头开始比较【j指向T首位】

直到完全匹配为止【j > T的长度】,否则匹配失败【i > S的长度】

时间复杂度:最坏情况为:主串n长,子串m长;除了最后一次,每一次都比较到子串最后一位发现不匹配,总共比较 m*(n-m+1)+m 次。时间复杂度 O(n*m)

四、KMP算法

改进BF算法:当字符不匹配时,利用已匹配部分的信息,仅让模式串回溯,主串不回溯

模式串要回溯到什么地方呢?目标地点记录在next[ ]数组中

next数组是干什么的呢?next数组记录了已匹配部分最大相同前后缀的信息

比如

S = a b a c c a b a b

P = a b a b

开始匹配

S = a b a c c a b a b

P = a b a

前三位都匹配,第四位b与c不匹配

此时我们知道已匹配的部分为a b a,它有相同的前后缀‘a

我们只需要让T的“前缀”与S的“后缀”对齐,接着比较即可。主串不需要回溯,子串也不用从头开始

S = a b a c c a b a b

P =       a b a b

next数组是一个与模式串等长的数组,它告诉我们,模式串第几位失配时我们要跳转到哪里

所以关键在于求next数组

1.求next数组

方法一

计算next数组流程图

方法二(考试方法)

假设next从j = 1开始编号

1)j = 1时,next[j] = 0

2)j > 1时,next[j] = j之前的最大相同前后缀长度 +1

3)j > 1时,找不到相同前后缀时,next[j] = 1

比如

方法二可以由方法一每位都加一得到,哪个舒服用哪个

2.KMP算法实现

方法一

完整例子,找到一段话中的所有匹配:

// 在一篇英文文章中查找指定的模式串,采用KMP算法实现
 
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
 
#define elemtype char
 
elemtype* getnext(elemtype* p)  //传入模式串得到next数组
{ 
	int pnum = strlen(p);
	elemtype* next = (elemtype*)malloc(sizeof(elemtype) * pnum);
	next[0] = 0;
	int len = 0;
	int k = 1;
 
	//生成next数组
	while (p[k] != '\0') 
    {
		if (p[len] == p[k])
			next[k++] = ++len;
		else
			(len == 0 ? next[k++] = 0 : len = next[len - 1]);
	}
 
	//调整next数组
	for (k = pnum - 2; k >= 0; k--)   
		next[k + 1] = next[k];
	next[0] = -1;
 
	//输出next数组
	printf("next数组为:");
	for (k = 0; k < pnum; k++)       
		printf("%d ", next[k]);
	printf("\n");
	return next;
}
 
void kmp(elemtype* s, elemtype* p) //传入两个串
{   
 
	elemtype* next = getnext(p);
 
	int i = 0;
	int j = 0;
	int flag = 1;
 
	while (flag == 1) {
		while (s[i] != '\0' && p[j] != '\0') 
        {
			if (j == -1 || s[i] == p[j])
            {
				i++;
				j++;
			}
			else  j = next[j];
		}
 
		if (p[j] == '\0') 
        {
			printf("字符串在编号%d处与模式串匹配\n", i - j);
			j = 0;   //匹配后模式串从头开始,继续寻找匹配点
		}
		else flag = 0;  //当字符串遍历完后才退出
	}
}
 
int main() {
 
	elemtype s[] = "No Person shall be a Senator who shall not have attained to the Age of thirty Years, and been nine Years a Citizen of the United States, "
					" and who shall not, when elected, be an Inhabitant of that State for which he shall be chosen.";
	elemtype p[] = "shall";	
	printf("字符串为:%s\n", s);
	printf("模式串为:%s\n", p);
 
	kmp(s, p);
}

方法二

3.nextval

有模式串p,next数组

数组都是从1开始编号

nextval计算方法

nextval[1] = 0

对于第i位,如果p[i] 不等于 p [ next [i] ] , nextval [i] = next [i]

                   如果p [i] 等于 p [ next [i] ],则 j = next [i],继续比较p [j] = p [ next [j] ],一直向前比较,直到不等或到首位为止

例一: 

字符串‘a b a b a a b a b’ 的next为:0 1 1 2 3 4 2 3 4;nextval为:0 1 0 1 0 4 1 0 1

例二:

求字符串‘a b c a a b b c a b c a a b d a b’的next和nextval

next:     0 1 1 1 2 2 3 1 1 2 3 4 5 6 7 1 2

nextval:0 1 1 0 2 1 3 1 0 1 1 0 2 1 7 0 1 

4.时间复杂度 

由于不用回溯,主串只走一遍,加上计算next时所用的比较次数m,为O(m+n)  BF为O(n*m)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

融资项目——swagger2的注解

1. ApiModel与ApiModelProperty(在实体类中使用) 如上图&#xff0c;ApiModel加在实体类上方&#xff0c;用于整体描述实体类。ApiModelProperty(value"xxx",example"xxx")放于每个属性上方&#xff0c;用于对属性进行描述。swagger2网页上的效果如下图&am…

c++内存池项目

文章目录 一、内存池介绍二、ThreadCache实现三、CentralCache实现四、PageCache实现五、回收内存六、大于256KB的内存申请与释放七、将new和delete换为定长内存池八、多线程环境下对比malloc进行基准测试九、使用基数树进行性能优化 一、内存池介绍 二、ThreadCache实现 下面…

Wordpress插件WP-Statistics无法识别来访IP国家和城市处理方法

Wordpress插件WP-Statistics&#xff0c;可以识别网站访问者的IP物理地址&#xff0c;统计出城市、国家&#xff0c;但最近发现都显示unknown/未知&#xff1a; 更新GeoIP数据库到最新还是不行&#xff1a; 偶然找到了之前能用的数据库&#xff0c;恢复回去&#xff0c;竟然大…

基于SpringBoot的桃花峪滑雪场租赁系统 JAVA简易版

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 游客服务2.2 雪场管理 三、数据库设计3.1 教练表3.2 教练聘请表3.3 押金规则表3.4 器材表3.5 滑雪场表3.7 售票表3.8 器材损坏表 四、系统展示五、核心代码5.1 查询教练5.2 教练聘请5.3 查询滑雪场5.4 滑雪场预定5.5 新…

【AI提示词人物篇】创新艺术未来,让科技改变想象空间

AI 绘画学习难度和练习技巧 学习绘画的技巧 学习能难度&#xff1a; 外貌特征&#xff1a;AI需要学习识别和理解各种外貌特征&#xff0c;如发型、肤色、眼睛颜色等。这可能需要大量的训练数据和复杂的模型架构。 镜头提示&#xff1a;AI需要学习理解不同镜头提示的含义&…

中心性算法归纳

中心性算法不仅是在我所学习的计算机网络当中起很重要的作用&#xff0c;在交通网络、社交网络、信息网络、神经网络当中也有很多的应用例子。今天我在这里总结一下场景的几种中心性算法。 参考文献 Python NetworkX库 偏心中心性&#xff08;Eccentricity Centrality&#x…

Kubernetes 的用法和解析(K8S 日志方案) -- 8

一、统一日志管理的整体方案 通过应用和系统日志可以了解Kubernetes集群内所发生的事情&#xff0c;对于调试问题和监视集群活动来说日志非常有用。对于大部分的应用来说&#xff0c;都会具有某种日志机制。因此&#xff0c;大多数容器引擎同样被设计成支持某种日志机制。 对…

安装vcpkg管理opencv的安装+MFC缺失的解决

第一步&#xff0c;出现#include没有办法找到opencv头文件的问题&#xff0c;无法解决 在VC的提示下&#xff0c;安装了vcpkg&#xff0c;然后用vcpkg命令来帮助安装opencv&#xff0c;过程十分顺利。 1. cmd 到命令行窗口&#xff1b; 2. 建立src文件夹&#xff0c;并进入…

KMP入门级别算法详解--终于解决了(next数组详解)

对于正常的字符串模式匹配&#xff0c;主串长度为m&#xff0c;子串为n&#xff0c;时间复杂度会到达O&#xff08;m*n&#xff09;&#xff0c;而如果用KMP算法&#xff0c;复杂度将会减少线型时间O&#xff08;mn&#xff09;。 设主串为ptr"ababaaababaa";&#…

MFC窗体背景颜色的设置、控件白色背景问题、控件文本显示重叠问题、被父窗体背景覆盖的问题

文章目录 设置mfc窗体背景颜色窗体设置背景颜色后解决控件白色背景解决重复修改控件文本后重叠的问题自绘控件被父窗体背景覆盖的问题 设置mfc窗体背景颜色 设置窗体的背景颜色非常简单&#xff0c;只需要在窗体的OnEraseBkgnd里面填充窗体背景就可以了&#xff0c;甚至直接画…

【SpringCloud】-GateWay源码解析

GateWay系列 【SpringCloud】-GateWay网关 一、背景介绍 当一个请求来到 Spring Cloud Gateway 之后&#xff0c;会经过一系列的处理流程&#xff0c;其中涉及到路由的匹配、过滤器链的执行等步骤。今天我们来说说请求经过 Gateway 的主要执行流程和原理是什么吧 二、正文 …

30. MVC设计模式

JavaEE 开发流程 ↓MVC的概念 MVC是Model-View-Controller的简称&#xff0c;即模型-视图-控制器。 MVC是一种设计模式&#xff0c;它把应用程序分成三个核心模块&#xff1a;模型、视图、控制器&#xff0c;它们各自处理自己的任务。 模型(model) 模型是应用程序的主体部分…

JavaEE进阶学习:Spring MVC 程序开发

1.什么是 Spring MVC Spring Web MVC 是基于Servlet API 构建的原始 Web 框架&#xff0c;从一开始就包含在Spring 框架中。它的正式名称 “Spring Web MVC” 来自其源模块的名称(Spring-webmvc)&#xff0c;但它通常被称为“Spring MVC”。 从上述定义我们可以得出两个关键信…

每日一题——轮转数组

1. 题目描述 给定一个整数数组nums&#xff0c;将数组中的元素向右轮转k个位置&#xff0c;其中k是非负数。 示例1: 输入&#xff1a;nums [1,2,3,4,5,6,7]&#xff0c;k 3 输出&#xff1a;[5,6,7,1,2,3,4] 解释&#xff1a; 向右轮转 1步&#xff1a;[7,1,2,3,4,5,6] 向右…

在Linux下探索MinIO存储服务如何远程上传文件

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、Cpolar杂谈 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. 创建Buckets和Access Keys二. Linux 安装Cpolar三. 创建连接MinIO服务公网地…

LED灯驱动模块加载与卸载代码框架

一. 简介 本文来编写 LED灯驱动模块加载与卸载的代码。 二. LED灯驱动模块加载与卸载代码框架 1. 创建工程 我的驱动代码存放目录&#xff1a; ubuntu系统 /home/wangtian/zhengdian_Linux/Linux_Drivers 目录下。 进入 /home/wangtian/zhengdian_Linux/Linux_Drivers 目…

Java开发框架和中间件面试题(4)

27.如何自定义Spring Boot Starter&#xff1f; 1.实现功能 2.添加Properties 3.添加AutoConfiguration 4.添加spring.factory 在META INF下创建spring.factory文件 6.install 28.为什么需要spring boot maven plugin? spring boot maven plugin 提供了一些像jar一样打包…

优先级队列与仿函数

优先级队列 优先级队列 priority_queue 是一种容器适配器&#xff0c;听起来是队列&#xff0c;其实它的底层数据结构是堆&#xff0c;所谓的优先级为默认越大的数优先级越高&#xff0c;即默认为大堆。 使用方式如下面的代码&#xff1a; #include<iostream> #includ…

做抖店需要保证金吗?总共需要多少资金?具体资金投入如下!

我是电商珠珠 做抖店需要保证金吗&#xff1f;这是很多想要入驻的新手常问的问题。我的回答是&#xff0c;需要&#xff01; 抖店平台之所以设立保证金&#xff0c;就是为了约束商家的行为&#xff0c;避免交易市场出现混乱&#xff0c;给用户一个良好的购物体验。 今天呢&a…

【性能优化】MySql数据库查询优化方案

阅读本文你的收获 了解系统运行效率提升的整体解决思路和方向学会MySQl中进行数据库查询优化的步骤学会看慢查询、执行计划、进行性能分析、调优 一、问题&#xff1a;如果你的系统运行很慢&#xff0c;你有什么解决方案&#xff1f; ​关于这个问题&#xff0c;我们通常首先…