【C语言数据结构7】--串的实现

article/2025/9/15 18:18:33

一、什么是串

串就是我们常说的字符串,它同样是一个线性表。可能有人认为串就是元素为字符的线性表,但这种说法是不准确的。对于普通的线性表,它们关注的往往是单个元素,每个单独的元素都有独立的含义。比如我们用线性表存储班级成绩,那么元素类型的定义应该如下:

typedef struct{char num[10];	//学号char name[10];	//姓名float scores;	//分数
}

假设表中存储了下面几个个元素:

学号姓名分数
1809111001zack97.5
1809111002rudy94
1809111003alice96
1809111004atom99

现在我们拿出学号为0104两个人的数据,我们只会说是两个人的成绩,或者排名前面的两个人。而不是用一个整体来称呼它们(通常情况是这样的)。

对于串来说,则有些不一样。比如下面这个字符串:

Do not go gentle into that good night!

我们取出一部分数据:

gentle

我们可以把它称为单词,我们再取出一部分:

good night!

我们可以说它是一个句子。正是因为串各的某个部分有整体意义,在串中我们需要实现对字串模式的操作。后面会详细介绍。

二、串的表示

这里我们使用顺序存储结构来表示一个串,结构和顺序表类似:

#define MAXSIZE 20
typedef struct{char ch[MAXSIZE+1];int length;
}SString;

这里我们创建了一个长度为MAXSIZE+1的char数组。其中下标为0的元素我们不存储数据,这是为了让逻辑位置和物理位置对应。其它和顺序表则是一样的。

除了上面的表示,还可以采用和C语言本身字符串一样的表示。我们不存储长度信息,而是通过\0这个字符来表示结尾。不过这种方式获取字符串长度的算法时间复杂度是O(n)。

三、串的实现

(1)串的赋值

串的赋值非常简单,就是一个简单的循环操作:

void StringAssign(SString *S, char *str){int i = 0;//如果当前字符不是\0while (s[i] != '\0'){//将字符数组的内容赋值给串S->ch[i+1] = s[i];++S->length;++i;}
}

因为数组的下标是从0开始的,因此将s[i]赋值给S->ch[i+1]。

(2)串的复制

复制操作和赋值操作类似,同样是一个简单的循环,只不过将赋值内容改成了一个串:

int StringCopy(SString *S1, SString S2){//如果串为空,则返回0if (!S2.length){return 0;}//循环遍历S2,将S2内容依次赋值给S1for(int i = 1; i <= S2.length; i++){S1->ch[i] = S2.ch[i];}//修改被赋值串S1的长度S1->length = S2.length;return 1;
}

我们不需要在意S1原本的内容,只需要将内容依次覆盖,然后修改S1的长度即可。这样逻辑上我们已经完成了串的赋值。而物理上S1的尾部可能有其它字符,不过我们不需要在意。

(3)求长度

我们直接返回串的length成员即是长度:

int StringLength(SString S){return S.length;
}

(4)串比较

串的比较就是各个字符ASCII数值的比较:

int StringCompare(SString S1, SString S2){//遍历S1,依次比较S1和S2的每个字符for(int i = 1; i < S1.length; i++){//如果不是同一个字符if(S1.ch[i] != S2.ch[i]){//返回它们的差值return S1.ch[i] - S2.ch[i];}}//返回长度的差值return S1.length - S2.length;
}

在循环中,我们判断了字符是否一样。如果不一样则返回S1当前字符和S2当前字符的差。我们判断字符串是通过第一个不匹配的字符来判断的。比如下面几对:

abc    >    abd
acd    >    add

如果每个对应字符都匹配成功,则比较串的长度。这里返回的是长度的差值,如果两个串一样,那函数会返回0。如果S1“大于”S2,那函数会返回大于0的数,否则返回小于0的数。

(5)截取字串

子串就是串中任意个连续的字符组成的串,比如我们有一个串:

Do not go gentle into that good night!

下面几个都是它的子串:

Donot
t go gentle
good

子串必须存在与原串,而且必须连续。

截取子串的操作很简单,这里只是单纯通过下标来截取:

int SubString(SString S1, SString *S2, int pos1, int pos2){//如果下标不合理,则返回0if(pos1 < 1 || pos2 > S1.length || pos2 <= pos1){return 0;}//将S1被截取的内容依次赋值给S2for(int i = pos1, j = 1; i <= pos2; i++, j++){S2->ch[j] = S1.ch[i];}//修改S2的长度S2->length = pos2-pos1;return 1;
}

下面我们来单独看两个操作,定位字串和模式匹配。

四、定位字串和模式匹配

定位子串的操作就是找到子串第一次出现在原串中的位置,比如我们有下面几个子串:

Do not go gentle into that good night!
Do
not
nt

其中Do的位置为1,not的位置为4,而nt在串中出现了两次,我们用第一次出现的位置表示,即13。下面我们就来看看怎么查找字串。

(1)定位子串

定位子串的操作就是不断对比串的过程,我们最开始将原串的指针i指向串首,取i到i+len的串与子串比较(其中len是子串的长度)。如图:

在这里插入图片描述

其中红框部分就是取出来与子串比较的部分。如果与子串相等,我们就返回i作为子串在原串中的位置。如果失败,则i++,直到i+len大于原串的长度。

代码实现如下:

int IndexSubString(SString S1, SString S2){//用于存储原串截取的部分SString temp;InitString(&temp);//如果子串长度大于if(S1.length < S2.length){return 0;}//循环比较原串和子串for(int i = 1; i+S2.length <= S1.length; i++){//截取原串内容SubString(S1, &temp, i, i+S2.length);//将截取内容与子串比较int result = StringCompare(temp, S2);//如果截取内容与子串相等,则返回i的值(子串的位置)if(result == 0){return i;}}return 0;
}

通常定位子串的前提是子串一定能在原串中找到。而上面是考虑了子串不存在的情况。而我们无法确定子串是否能在原串中找到时做的定位操作叫模式匹配。不过模式匹配还包括了一些特殊规则的匹配、因此模式匹配的含义要更丰富。

(2)模式匹配

上面的算法我们特意截取出一个临时串用于比较,这一步其实是没必要的,这里为了让大家看代码更轻松才这样安排。不借助辅助串的代码如下:

int IndexSubString(SString S, SString T) {//指向被比较子串的首位置int k = 1;//分别指向原串中被比较的位置和模式串中被比较的位置int i = k, j = 1;//循环比较while (k <= S.length && j <= T.length){if(S.ch[i] == T.ch[j]){//当前字符匹配成功则继续匹配i++;j++;}else{//当前字符匹配失败则将k指向下一个子串,i与k同步k++;i=k;j=1;}}//防止原串字符不够if(j > T.length)return k;elsereturn 0;
}

k、i、j三个指针指向的位置如图所示:

在这里插入图片描述

而在循环过后我们还判断了j是否大于S2.length,这里大家可以模拟匹配下面串的过程:

abaccdo
cdoo

当我们匹配到末尾时,循环可以正常退出。但是j指针指向模式串的第一个o,这时我们算法应该返回匹配失败的信号。这就是最后的if语句的作用了。

准确来说,上面两个算法都是模式匹配算法。在串中还有一个重要的KMP算法,由于篇幅限制,KMP算法将单独写一篇文章。


http://chatgpt.dhexx.cn/article/pP0hLwgc.shtml

相关文章

C语言数据结构——查找(检索)

一、查找的基本概念 查找:查询某个关键字是否在(数据元素集合&#xff09;表中的过程。也称作检索。 查找表: 由同一类型的数据元素&#xff08;或记录&#xff09;构成的集合。 主关键字: 能够惟一区分各个不同数据元素的关键字 次关键字: 通常不能惟一区分各个不同数据元素的…

C语言数据结构——广义表

C语言数据结构中&#xff0c;广义表和数组一样&#xff0c;也是线性表的一种推广&#xff01; 广义表的定义&#xff1a; 广义表 LS 为n&#xff08;n≥0&#xff09;个元素的有穷序列&#xff0c;记作&#xff1a; LS &#xff08;d1, d2, … dn&#xff09; 其中&#xff1…

C语言数据结构——图

一、图的基本概念 图是由顶点集合及顶点间的关系集合组成的一种数据结构。vertex, edge 图G的定义是&#xff1a; G &#xff08;V&#xff0c;E&#xff09; 其中&#xff0c; V {x|x∈某个数据元素集合} E { (x&#xff0c;y)|x&#xff0c;y∈V} &#xff08;无向图&#…

数据结构(c语言版本)

1.基本概念 1.1数据 对客观事物的符号表示&#xff0c;在计算机与科学中是指所有能输入到计算机并被计算机程序处理的符号的总称。 1.2数据元素 是数据的基本单位&#xff0c;在计算机程序中作为一个整体进行考虑和处理 1.3数据对象 是相同性质数据元素的集合&#xff0c…

c语言数据结构

目录 一、数据结构构造概述 1.1、什么是数据结构 1.2、数据的逻辑结构的4种分类 二、线性表 2.1、线性表概述 2.2、顺序表 2.3、链表 2.3.1、链表节点的创建 2.3.2、链表结点遍历 2.3.3、链表结点删除 2.3.4、链表的插入 ​ 三、栈和队列 3.1、栈概述 3.2、栈…

C语言数据结构知识点小结(全)

Catologue C语言数据结构一、基本概念和术语二、时间、空间复杂度&#xff08;1&#xff09;时间复杂度&#xff08;2&#xff09;空间复杂度 三、类C语言有关操作补充1&#xff1a;数组定义补充2&#xff1a;动态内存分配补充3&#xff1a;C中的参数传递 四、线性表&#xff0…

七丶青龙nvjdc部署教程+短信验证登录对接傻妞

青龙nvjdc部署教程短信验证登录对接傻妞Nolanjdc 没有服务器的先自行购买&#xff0c;这里推荐腾讯云2H4G8M首年70–点击购买 青龙面板安装教程 傻妞机器人安装教程 XDD安装教程 QQ交流&#xff1a;1014549449 --------------点击跳转 注丶只能对接一个&#xff0c;要么对接…

手机短信验证

在项目中经常会用到手机短信验证注册&#xff0c;登录等功能&#xff0c;所以我想写一篇文章来给大家提供一个参考。 阿里大于-个人感觉比较好用的短信验证平台&#xff0c;下面是接入阿里大于sdk的步骤。 阿里大于官网&#xff1a;直通车, 进入官网需要注册&#xff0c;注册…

014_关于session实现短信验证登录的前端启动

014_关于session实现短信验证登录的前端启动 1、进入到nginx相对应的文件夹&#xff0c;shfit右键&#xff0c;进入PowerShell并且执行nginx 2、启动我们的nginx,嘿嘿&#xff0c;可以访问我们的前端网页啦&#xff01;&#xff01;&#xff01;它就是模仿我们的大众点评来着…

基于Redis的短信验证登录

基于Redis的短信验证登录 1、用户调用发送短信验证码接口2、用户调用登录/注册接口3、用户调用校验接口4、SpringMvc拦截器注册5、token刷新拦截器6、登录拦截器 1、用户调用发送短信验证码接口 用户调用sendCode()接口&#xff0c;把phone传到后端&#xff0c;后端对phone进行…

使用聚合数据短信API测试(短信验证登录)

搞一手聚合数据短信API测试&#xff08;之前用阿里云的搞过&#xff0c;今天我们用聚合&#xff09; 注册聚合账号&#xff01;聚合官网链接登陆后进入短信服务API&#xff08;免费提供十次&#xff09; 添加自定义模板&#xff08;审核速度看脸&#xff09; 审核成功后得…

android studio 实现短信验证 登录

登录 http://www.mob.com/ 注册 创建项目 加入依赖 贴代码 classpath “com.mob.sdk:MobSDK:2018.0319.1724” apply plugin: ‘com.mob.sdk’ // 在MobSDK的扩展中注册SMSSDK的相关信息 这里使用自己的 appKey appSecret MobSDK {appKey “2e2974aec0” appSecret “1d35b87…

Java简单实现短信验证登录(Session、Redis)

前端设计 <div class"login-form"><div style"display: flex; justify-content: space-between"><el-input style"width: 60%" placeholder"请输入手机号" v-model"form.phone" ></el-input><e…

Vue与Node.js实现手机短信验证登录

手机短信使用的第三方平台是联容云&#xff0c;注册就送8块钱体验费&#xff0c;足够自己用用了&#xff0c;注册完自己建一个应用就能拿到需要使用的配置了&#xff0c;如图 注册完之后1就可以使用了。 Node.js后端使用了Express框架 "js-base64": "^3.7.2&qu…

【青龙面板+诺兰2.0 网页短信验证登录+bot查询】

看这个之前&#xff0c;如果是没搭建过的先看下面这篇哈&#xff0c;如果是跟着下面的搭建完了&#xff0c;出现了机器人5次获取验证码失败&#xff0c;让你用Cookie方式登录的情况&#xff0c;看这篇哈。 前提&#xff1a;自己有服务器&#xff01;这里用的Centos7.6做演示&am…

Springboot实现短信登录验证

Springboot学习笔记——Java实现短信登录验证功能--Servlet/SSM/SpringBoot都可以用 小白记录一下短信验证登入的实现&#xff0c;方便以后可以拿来直接用。 发短信平台&#xff1a;互亿无线 官网地址 登入注册啥的就不说了&#xff0c;新人注册会送十条短信验证&#xff0c;想…

java WEB调用秒嘀科技短信验证接口(实现短信验证登录)

java WEB调用秒嘀科技短信验证接口&#xff08;实现短信验证登录&#xff09; 前言注册秒嘀云账号登录秒嘀云官网 代码 前言 短信验证登咱就不多说了&#xff0c;为什么推荐用秒嘀的呢&#xff0c;应为他会送你10元钱&#xff0c;对于新手来说10元钱&#xff0c;足够你玩了。但…

Android利用mob实现短信验证登录

首先要去官网申请一个应用&#xff0c;拿到对应的APPKEY以及APPSECRET 附上直通车链接MobTech 申请应用基本是秒批&#xff0c;然后就可以得到应用的APPKEY以及APPSECRET 然后就是查看官方的文档 直接跟着步骤走&#xff0c;可以不用手动下载sdk&#xff0c;导入这些它自动会帮…

微信小程序短信验证登录

首先小程序wxml页面 <!--pages/logins/logins.wxml--> <view class"container"><view class"title">登录</view><form catchsubmit"login"><view class"inputView"><input class"inputT…

Springboot实现短信验证登录

一、介绍 使用短信验证登录也是现在实际项目中普遍使用的一种登录, 二、实际的操作流程 1.用户在前端页面输入手机号码之后,点击发送验证码 2.前端将手机号传给后端 3.后端生成一个6为的随机数通过短信发送给用户,之后将手机号设为key,验证码设为value存入redis缓存中…