数据结构-----串(String)详解

news2024/11/20 20:37:50

目录

前言

1.串的定义

相关类型

2.串的储存结构

顺序储存表示

堆分配储存表示

块链储存表示

3.串的操作方式

4.串的匹配算法

(1)BF算法

过程原理 

代码实现(C/C++) 

算法分析

(2)KMP算法

过程原理

匹配过程: 

 获取next数组:

代码实现(C/C++)

算法分析


前言

        前面我们学习了顺序表和线性表,这两种数据结构的储存数据域可以是一个任意类型,比如:整形、字符串类型、含有多种类型的结构体等等……那今天我们学习新的数据结构--串,其数据域的类型只能是字符类型,下面就一起来看看吧!

1.串的定义

  • 是由零个多个字符数组组成的有限序列。
  • 串中字符的个数称为串的长度,含有零个元素的叫空串。
  • 串是限定了元素为字符的线性表

(注:串与一般的线性表操作有很大区别,线性表主要针对表内的某个元素,而串操作主要针对子串

相关类型

  • :0个或多个字符组成的有限序列。S=′a1​a2​...an′​(n>=0)。
  • 串的长度:串中字符的个数
  • 空串:长度为0的串
  • 空格串:0个或多个空格字符组成的串
  • 子串:串中任意连续字符组成的子序列
  • 主串:包含子串的串
  • 位置:字符在串中的序号。ps:子串在主串中的位置是其第一个字符在主串中的位置。
  • 串的相等:长度和对应位置字符都相等

2.串的储存结构

顺序储存表示

 顺序储存结构是通过用一个连续地址的区域去储存字符数据,实际上就是数组的形式去储存。顺序储存方式必须去规定好最大储存值,储存的数量不能超过规定的最大值,超过的部分就要被舍去。顺序储存结构如下所示:

#define Maxsize 256//定义最大容量
//顺序储存
typedef struct string {
	char ch[Maxsize];//储存字符串
	int length;		//当前串的长度
}String;

堆分配储存表示

 堆分配储存方式是通过空间的动态分配内存来去储存数据的,然后通过指针域把堆里面分配好的不连续空间给链接到一起,形成链表。虽然是动态分配可以根据实际情况去分配容量,但是由于指针域占用4个字节的空间,然而数据域仅仅只占用1个字节空间,这就会有点浪费空间,所以很多时候我们会去用顺序储存方式来去实现一个串。堆分配储存结构如下所示:

typedef struct string {
	char ch;	//数据域
	struct string* next;//指针域
}String;

块链储存表示

 块链的储存结构是对堆分配储存方式的改进,就是提高了数据域的空间占用比,提高空间的利用率,一个节点可以去存放多个字符,如下所示:

3.串的操作方式

以下就是对字符串的操作方法,跟我们前面所学的顺序表和链表的操作方法基本上没有太大区别,这里我就不去一一详细讲了,有兴趣的小伙伴可以去自己把代码写完整实现这些功能。 

StrAssign(&T, chars);// 赋值操作。把串T赋值为 chars

Strcopy(&T, S);// 复制操作。把串S复制得到串T。

StrEmpty(S);// 判空操作。若S为空串, 则返回TRUE, 否则返回 FALSE

Replace(&S, T, V);//串的替换操作,把T替换为V

StrCompare(S, T);// 串比较操作。若S > T, 则返回值 > 0; 若S = T, 则返回值 = 0; 若S < T, 则返回值 < 0。

StrEngth(S);// 求串长。返回串S的元素个数

Substring(&Sub, S, pos, 1en);// 求子串。用Sub返回串S的第pos个字符起长度为len的子串。

Concat(&T, S1, S2);// 串联接。用T返回由S1和S2联接而成的新串。

StrInsert(&S, pos, T);//串的插入操作。把T插入到S的pos位置上

Index(S, T);// 子串的定位操作。若主串S中存在与串T值相同的子串, 则返回它在主串S中第一次出现的位置; 否则函数值为0
Clearstring(&S);// 清空操作。将S清为空串

Destroystring(&S);// 销毁串。将串S销毁
	

 下面我要重点讲的是字符串的查找匹配,也就是在一个主串中匹配里面是否有满足条件的子串,下面就来看看吧!

4.串的匹配算法

(1)BF算法

         BF算法,即暴力(Brute Force)算法,是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符;若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。BF算法是一种蛮力算法

过程原理 
代码实现(C/C++) 
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#define Maxsize 256
//顺序储存
typedef struct string {
	char ch[Maxsize];//储存字符串
	int length;		//当前串的长度
}String;

//01---串的模式匹配算法  暴力查找法
int Index_BF(String* S, String* T) {
	assert(S);
	assert(T);
	int i = 0, j = 0;
	while (i < S->length && j < T->length) {
		if (S->ch[i] == S->ch[i])	//当匹配到相同的时候
		{
			i++;		//主串和模式串的指针指向 依次+1
			j++;
		}
		else
		{
			i = i - j + 1;//主串回溯到后面一个字符
			j = 0;			//模式串回溯到第一个字符
		} 
	}
	if (j == T->length)
		return i-j+2;	//返回匹配成功主串的位置
	return -1;
}
算法分析

 可以看出BF算法确实很暴力,一个一个去一一匹配,直到成功为止,所以时间复杂度为O(mn),m是主串的长度,n是模式串的长度

(2)KMP算法

        KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。

过程原理

 KMP算法可以很大限度减少匹配的次数,也就是说主串不需要去执行回溯的操作,从而提高匹配的效率,但是KMP算法还是有点难去理解的,需要用到一个next数组(可能失配位置),下面我会去详细说明的。

匹配过程: 

假设

主串:    a b c d a b e a b c d a b

模式串:a b c d a b d

第一次匹配 

a b c d a b e a b c d a b d

a b c d a b d

很明显第六个(d和e)出现了不同,在此之前前面出现相同的字符最大个数是2(分别是a、b)。

 第二次匹配

前面我们知道模式串出现相同字符最大个数为2,此时直接把子串相同字符的位置移动到以下位置:

a b c d a b e a b c d a b d

            a b c d a b d

这里我们可以发现主串跟模式串中的第三个字符不相匹配,所以此时要把模式串的第一个位置与 e 进行比较

第三次匹配

 a b c d a b e a b c d a b d

                   a b c d a b d

很显然此时模式串的第一个字符与主串不匹配,所以需要将主串的比较位置往后移动一位,模式串也是一样往后移动一位,再次比较

第四次匹配

 a b c d a b e a b c d a b d

                      a b c d a b d

此时匹配成功,返回主串匹配成功第一个字符的位置(主串中 a 的位置

 获取next数组:

对于模式串: a b c d a b d 

1.首位字符 a 前面是没有字符的,故没有前缀也没有后缀,那么其next数组值为-1,即next[ 0 ]=-1

2.对于第二个字符b 其前面的前缀和后缀都是字符a都是同一个,所以不能表示前缀与后缀相等,故其next数组值为0,即next[1]=0

3.对于第三个字符c其前面前缀a ,  b不相等,所以没有前缀与后缀相等,故next[2]=0

4.对于第四个字符d其前缀有a,ab,后缀有bc,c,故前缀与后缀都不相等,所以next[3]=0

5.对于第五个字符a其前缀有a,ab,abc后缀有bcd,cd,c同样也是不相等,所以next[4]=0

6.对于第六个字符b其前缀有a,ab,abc,abcd,后缀有bcda,cda,da,a,这里我们发现有一个前缀与后缀相等那就是 a 所以next[5]=1

7.对于第七个字符d其前缀有a,ab,abc,abcd,abcda,后缀有bcdab,cdab,dab,ab,a其相等的前缀和后缀一共有两个,所以next[6]=2

                               a          b           c             d          a            b        d 

                         next[0]    next[1]   next[2]   next[3]  next[4]  next[5]  next[6]

next数组的值:      -1            0            0             0        0            1           2

注意:next数组的值只跟模式串有关,与主串无关       

 下面给大家一个其他模式串的示例,你们也可以试着看怎么去求得next数组

代码实现(C/C++)
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#define Maxsize 256
//顺序储存
typedef struct string {
	char ch[Maxsize];//储存字符串
	int length;		//当前串的长度
}String;

//02---串的模式匹配算法  KMP算法
//next 数组获取
int* Next(String* S) {
	assert(S);
	int* next = (int*)malloc(sizeof(int) * S->length);//开辟一个跟模式串一样长度的数组next
	int j = -1, i = 0;	//初始化
	next[0] = -1;	//初始化
	while (i < S->length-1) {
		if (j == -1 || S->ch[i] == S->ch[j]) {	//当j为-1时候,也就是主串和模式串字符不匹配时;或者主串和模式串字符匹配的时候,进行next 数组赋值操作
			i++;
			j++;
			next[i] = j;	//如果不匹配的话,此时next数组当前的位置赋值为0,如果匹配的话就依次+1
		}
		else {
			j = next[j];	
		}
	}
	return next;
}

//算法接口
int Index_KMP(String* S, String* T) {
	assert(S);
	assert(T);
	int i = 0, j = 0;
	int* next = Next(&T);
	while (i < S->length && j < T->length) {
		if (S->ch[i] == S->ch[i])
		{
			i++;
			j++;
		}
		else
		{
			//这里对比与BF算法,就少了主串i的回溯
			j = next[j];	//模式串j就直接移到next数组当前的位置
		}
	}
	if (j == T->length)
		return i - j + 2;
	return -1;
}
算法分析

可以看出相较于BF算法,KMP算法大大提高了匹配效率,时间复杂度为O(m+n),m为主串长度,n为模式串长度

以上就是本期的全部内容,你们学会了吗?我们下一期再见咯!

分享一张壁纸:

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

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

相关文章

2.(vue3.x+vite)组件注册并调用

前端技术社区总目录(订阅之前请先查看该博客) 关联博客 1.(vue3.x+vite)封装组件 一:umd调用方式 1:引入umd.js <script src="./public/myvue5.umd.js"></script>2:编写代码调用 (1)umd方式,根据“5

四川天蝶电子商务有限公司真实吗?

四川天蝶电子商务有限公司是一家专注于电商行业的企业&#xff0c;他们通过自己的经验和专业知识&#xff0c;教人带货的方法和技巧。带货是指通过社交媒体或其他渠道&#xff0c;向消费者推销商品并实现销售的过程。 教人带货的方法主要有以下几点&#xff1a; 1.选择合适的平…

以酒为媒、以酒载道,五粮液携手首届“金熊猫奖”,讲好中国白酒故事

执笔 | 尼 奥 编辑 | 萧 萧 这是一次光影艺术与白酒酿造的和美之约&#xff0c;也是中国文化与世界多元文明的交融时刻&#xff0c;在影视与美酒的碰撞瞬间&#xff0c;共同擘画“美美与共&#xff0c;天下大同”的文明图景。 9月19-20日&#xff0c;以“多彩文明荣耀光影…

Webshell 流量特征分析

前言&#xff1a;webshell是以asp、php、jsp或者cgi等网页文件形式存在的一种代码执行环境&#xff0c;主要用于网站管理、服务器管理、权限管理等操作。使用方法简单&#xff0c;只需上传一个代码文件&#xff0c;通过网址访问&#xff0c;便可进行很多日常操作&#xff0c;极…

2023-2024年最新大数据学习路线

文章目录 2023-2024年最新大数据学习路线大数据开发入门*01*阶段案例实战 大数据核心基础*02*阶段案例实战 千亿级数仓技术*03*阶段项目实战 PB级内存计算04阶段项目实战 亚秒级实时计算*05*阶段项目实战 大厂面试*06* 2023-2024年最新大数据学习路线 新路线图在Spark一章不再…

CSS 基础 3

目录 &#x1f680; 导读 -- target 盒子模型 看透网页布局的本质 盒子模型组成 边框(border) border-style ​编辑border-color border-width 边框写法 简写 分开写 表格细线边框 边框会影响盒子实际大小 内边距 内容 内边距-padding padding属性简写 pad…

vue点击pdf文件直接在浏览器中预览文件

好久没有更新文章了&#xff0c;说说为什么会有这篇文章呢&#xff0c;其实是应某个热线评论的要求出的&#xff0c;不过由于最近很长一段时间没打开csdn现在才看到&#xff0c;所以才会导致到现在才出。 先来看看封装完这个预览方法的使用&#xff0c;主打一个方便使用&#x…

Java学习day06:面向对象基础,构造方法,成员/局部变量

声明&#xff1a;该专栏本人重新过一遍java知识点时候的笔记汇总&#xff0c;主要是每天的知识点题解&#xff0c;算是让自己巩固复习&#xff0c;也希望能给初学的朋友们一点帮助&#xff0c;大佬们不喜勿喷(抱拳了老铁&#xff01;) Java学习day06&#xff1a;面向对象基础&a…

网络爬虫相关概念

目录 1、什么是爬虫&#xff1f; 2、网络爬虫步骤 3、爬虫核心 4、爬虫的用途 5、爬虫分类 6、反爬手段 1、什么是爬虫&#xff1f; 如果我们把互联网比作一张大的蜘蛛网&#xff0c;那一台计算机上的数据便是蜘蛛网上的一个猎物&#xff0c;而爬虫程序就是一只小蜘蛛&am…

给定一个链表,判断链表中是否有环

【思路】 快慢指针&#xff0c;即慢指针一次走一步&#xff0c;快指针一次走两步&#xff0c;两个指针从链表其实位置开始运行&#xff0c; **如果链表带环则一定会在环中相遇&#xff0c;**否则快指针率先走到链表的末尾。比如&#xff1a;陪女朋友到操作跑步减肥。 bool hasC…

测试域: 流量回放-工具篇jvm-sandbox,jvm-sandbox-repeater,gs-rest-service

JVM-Sandbox Jvm-Sandbox-Repeater架构_小小平不平凡的博客-CSDN博客 https://www.cnblogs.com/hong-fithing/p/16222644.html 流量回放框架jvm-sandbox-repeater的实践_做人&#xff0c;最重要的就是开心嘛的博客-CSDN博客 [jvm-sandbox-repeater 学习笔记][入门使用篇] 2…

Unity丨自动巡航丨自动寻路丨NPC丨

文章目录 概要功能展示技术细节小结 概要 提示&#xff1a;这里可以添加技术概要 本文功能是制作一个简单的自动巡逻的NPC&#xff0c;随机自动寻路。 功能展示 技术细节 using UnityEngine;public class NPCController : MonoBehaviour {public float moveSpeed 5.0f; // …

成都瀚网科技:抖音提供差异化​​亮点!

在抖音平台上&#xff0c;精选联盟是一个专门为优质品牌提供展示和推广机会的合作项目。对于斗店主来说&#xff0c;如何成功对接精选联盟并实现上市是一个重要目标。在这篇文章中&#xff0c;我们将分享一些豆点与精选联盟对接的方法&#xff0c;并提供上币指南。 1、提升店铺…

2023最新如何轻松升级、安装和试用Navicat Premium 16.2.10 教程详解

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

六、决策树算法(DT,DecisionTreeClassifier)(有监督学习)

决策树&#xff08;DT&#xff09;是一种用于分类和回归的非参数监督学习方法。其目标是创建一个模型&#xff0c;通过学习从数据特征中推断出的简单决策规则来预测目标变量的值。一棵树可以看作是一个片断常数近似值。 一、算法思路 具体可参考博文&#xff1a;七、决策树算…

linux升级glibc-2.28

1.准备工作 1.1升级gcc到gcc8 # 安装devtoolset-8-gcc yum install centos-release-scl yum install devtoolset-8 scl enable devtoolset-8 -- bash# 启用工具 source /opt/rh/devtoolset-8/enable # 安装GCC-8 yum install -y devtoolset-8-gcc devtoolset-8-gcc-c devtoolse…

【C语言】数组和指针刷题练习

指针和数组我们已经学习的差不多了&#xff0c;今天就为大家分享一些指针和数组的常见练习题&#xff0c;还包含许多经典面试题哦&#xff01; 一、求数组长度和大小 普通一维数组 int main() {//一维数组int a[] { 1,2,3,4 };printf("%d\n", sizeof(a));//整个数组…

[plugin:vite:css] [sass] Undefined mixin.

前言&#xff1a; vite vue3 TypeScript环境 scss报错&#xff1a; [plugin:vite:css] [sass] Undefined mixin. 解决方案&#xff1a; 在vite.config.ts文件添加配置 css: {preprocessorOptions: {// 导入scss预编译程序scss: {additionalData: use "/resources/_ha…

如何使用远程桌面软件进行远程工作

远程工作提供了更大的灵活性和自由度&#xff0c;使得可以在任何地点工作。而要实现高效的远程工作&#xff0c;一个关键的工具就是远程桌面软件。本文将详细介绍如何使用远程桌面软件进行远程工作&#xff0c;以帮助读者提高工作效率。 一、了解远程桌面软件的基本原理 远程桌…