【数据结构】四、串

news2024/11/24 15:10:55

目录

一、定义

二、表示与实现

定长顺序存储

堆分配存储

链式存储

三、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)

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

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

相关文章

pip 常用指令 pip config 命令用法介绍

&#x1f4d1;pip 常用命令归类整理 pip config 是一个用于管理本地和全局配置的命令行工具。它允许用户获取和设置所有的 pip 配置值。 命令 pip config 有以下参数 list&#xff1a;列出所有的 pip 配置值。edit&#xff1a;编辑 pip 配置文件。get&#xff1a;获取一个配…

时间是如何定义的

每年365天&#xff0c;每天24小时&#xff0c;每小时60分钟&#xff0c;每分钟60s&#xff0c;这是我们习以为常的时间计量单位&#xff0c;那么在继续往下&#xff0c;1s是多少&#xff1f;几时几刻、几点几分是如何确定的&#xff1f;带着这些问题&#xff0c;展开本文。 1、…

如何在 openKylin 上使用 ONLYOFFICE 桌面编辑器

文章作者&#xff1a;ajun ONLYOFFICE 桌面编辑器是一款基于依据 AGPL v.3 许可进行分发的开源办公套件。使用这款应用&#xff0c;您无需保持网络连接状态即可处理存储在计算机上的文档。 本文章基于中国根操作系统 openKylin 操作系统&#xff0c;使用软件商店快速安装与手…

rtsp视频在使用unity三维融合播放后的修正

1 rtsp 接入 我们使用unity UE 等三维渲染引擎中使用c编写插件来接入rtsp 视频。同时做融合的时候&#xff0c;和背景的三维颜色要一致&#xff0c;这就要使用视频融合修正技术。包括亮度&#xff0c;对比度&#xff0c;饱和度的修正。在单纯颜色上的修正可以简单使用rgb->…

Android 权限申请

在Android中&#xff0c;从Android 6.0&#xff08;API级别23&#xff09;开始&#xff0c;应用在运行时需要动态申请权限。以下是一些步骤来动态申请权限&#xff1a; 在应用的清单文件&#xff08;AndroidManifest.xml&#xff09;中声明需要的权限。例如&#xff0c;如果应…

前端FLV视频直播解决方案

项目背景&#xff1a; 1. 后台给出一个地址&#xff0c;持续不断的推送flv视频流。 2.前端需要接收视频流&#xff0c;并寻找合适的播放插件。 一开始&#xff1a; 其实用的是xgplayer&#xff08;西瓜视频&#xff09;。 官网地址&#xff1a;西瓜播放器 使用的是直播&a…

ardupilot开发 --- 风机不停机巡检 篇

在哪里创建的siyi实例&#xff1f; 如何传递飞控的时间戳给siyi相机&#xff1f; AP_RTC_ENABLED在waf编译时配置为1&#xff1f;&#xff1f; 如何配置&#xff1f; 在lua脚本中如何获取这个时间AP::rtc().get_utc_usec(utc_usec)&#xff1f;&#xff1f;&#xff1f; inclu…

【软件问题】解决 SecoClient 提示:接收返回码超时!

解决 SecoClient 提示&#xff1a;接收返回码超时&#xff01; 1.问题描述2.问题查找3.问题解决 系统&#xff1a;Win10 1.问题描述 这段时间因为不小心得了流感&#xff0c;所以需要请病假&#xff0c;而有些工作还得做不能落下&#xff0c;所以得居家办公&#xff0c;因为我…

【深入解析spring cloud gateway】12 gateway参数调优与分析

本节主要对网关主要的一些参数做一些解释说明&#xff0c;并用压测工具测试一下网关的接口&#xff0c;通过压测来验证参数配置是否合理 一、连接池参数 参数示例 spring:application:name: gatewaycloud:gateway:# http连接设置httpclient:# 全局的响应超时时间&#xff0c…

大语言模型(LLM)与 Jupyter 连接起来了!

现在&#xff0c;大语言模型&#xff08;LLM&#xff09;与 Jupyter 连接起来了&#xff01; 这主要归功于一个名叫 Jupyter AI 的项目&#xff0c;它是官方支持的 Project Jupyter 子项目。目前该项目已经完全开源&#xff0c;其连接的模型主要来自 AI21、Anthropic、AWS、Co…

【Git】在 IDEA 中合并多个 commit 为一个

文章目录 1 未提交到远程分支1.1 需求说明1.2 reset 操作1.3 再次 push 2 已经提交到远程分支2.1 需求说明2.2 rebase 操作2.3 强制 push 分两种情况&#xff1a; 一种是本地提交还没推到远程&#xff0c;这种好处理另一种是已经提交到远程分支&#xff0c;这个略麻烦 1 未提…

【Java代码审计】RCE篇

【Java代码审计】RCE篇 1.Java中的RCE2.ProcessBuilder命令执行漏洞3.Runtime exec命令执行漏洞4.脚本引擎代码注入5.RCE的防御 1.Java中的RCE 在PHP开发语言中有system()、exec()、shell_exec()、eval()、passthru()等函数可以执行系统命令。在Java开发语言中可以执行系统命令…

如何从 Android 手机免费恢复已删除的通话记录/历史记录?

有一个有合作意向的人给我打电话&#xff0c;但我没有接听。更糟糕的是&#xff0c;我错误地将其删除&#xff0c;认为这是一个骚扰电话。那么有没有办法从 Android 手机恢复已删除的通话记录呢&#xff1f;” 塞缪尔问道。如何在 Android 上恢复已删除的通话记录&#xff1f;如…

STM32CubeMX驱动ST7789

环境 1、单片机:STM32F103C8T6 2、开发平台&#xff1a;STM32CUBEMXkeil mdk 3、屏幕&#xff1a;ST7789&#xff0c;分辨率240*240 STM32配置 1、使用硬件SPI1驱动屏幕。配置如下&#xff1a; 2、屏幕控制引脚配置&#xff1a; 注意&#xff1a;只配置了DC,RST,CS这3个控…

BearPi Std 板从入门到放弃 - 后天篇(3)(ESP8266透传点灯)

简介 电脑搭建一个TCP Server&#xff0c; ESP8266 串口设置好透传模式, 再由TCP Server发送指令控制灯的亮灭; 开灯指令&#xff1a; led_on回车 &#xff1b; 关灯指令: led_off回车 主芯片: STM32L431RCT6 LED : PC13 \ 推挽输出即可 \ 高电平点亮 串口: Usart1 / LPUART E…

html之如何设置音频和视频

文章目录 前言一、音频标签&#xff1a;audio1.audio简介2.常用属性controlsautoplayloop代码演示&#xff1a; 二、视频标签&#xff1a;video1.video2.常用的视频元素controlsautoplayloop代码演示&#xff1a; 总结视频元素总结音频元素总结 前言 html中插入音频和视频的方…

网络通信--深入理解网络和TCP / IP协议

计算机网络体系结构 TCP/IP协议族 TCP / IP 网络传输中的数据术语 网络通信中的地址和端口 window端查看IP地址和MAC地址&#xff1a;ipconfig -all MAC层地址是在数据链路层的&#xff1b;IP工作在网络层的 MAC是48个字节&#xff0c;IP是32个字节 在子网&#xff08;局域…

4 postman响应数据解析

上一篇:3 使用postman批量创建测试数据-CSDN博客 在接口测试中,从接口的响应结果中获取数据是很常用的。比如说做断言的时候,需要确保接口返回数据是符合预期的。又比如有些接口的输入参数值,需要用到前面接口运行返回的数据。下面先介绍如何解析响应数据(以json数…

轻量封装WebGPU渲染系统示例<54>- 拱形门

当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/material/src/voxgpu/sample/GLBMaterialTest.ts 当前示例运行效果:

vue中最重要的点,双向数据绑定是什么?

一、什么是双向绑定 我们先从单向绑定切入单向绑定非常简单&#xff0c;就是把Model绑定到View&#xff0c;当我们用JavaScript代码更新Model时&#xff0c;View就会自动更新双向绑定就很容易联想到了&#xff0c;在单向绑定的基础上&#xff0c;用户更新了View&#xff0c;Mo…