数据结构与算法教程,数据结构C语言版教程!(第四部分、字符串,数据结构中的串存储结构)二
第四部分、字符串,数据结构中的串存储结构
串存储结构,也就是存储字符串的数据结构。
很明显,字符串之间的逻辑关系也是“一对一”,用线性表的思维不难想出,串存储结构也有顺序存储和链式存储。
提到字符串,常做的操作就是串之间的匹配,因为,本章给初学者介绍 2 种串的模式匹配算法,BF 算法和 KMP 算法。
三、串的堆分配存储结构
串的堆分配存储,其具体实现方式是采用动态数组存储字符串。
通常,编程语言会将程序占有的内存空间分成多个不同的区域,程序包含的数据会被分门别类并存储到对应的区域。拿 C 语言来说,程序会将内存分为 4 个区域,分别为堆区、栈区、数据区和代码区,其中的堆区是本节所关注的。
与其他区域不同,堆区的内存空间需要程序员手动使用 malloc 函数申请,并且在不用后要手动通过 free 函数将其释放。
C 语言中使用 malloc 函数最多的场景是给数组分配空间,这类数组称为动态数组。例如:
char * a = (char*)malloc(5*sizeof(char));
此行代码创建了一个动态数组 a,通过使用 malloc 申请了 5 个 char 类型大小的堆存储空间。
动态数组相比普通数组(静态数组)的优势是长度可变,换句话说,根据需要动态数组可额外申请更多的堆空间(使用 relloc 函数):
a = (char*)realloc(a, 10*sizeof(char));
通过使用这行代码,之前具有 5 个 char 型存储空间的动态数组,其容量扩大为可存储 10 个 char 型数据。
下面给大家举一个完整的示例,以便对串的堆分配存储有更清楚地认识。该程序可实现将两个串("data.bian" 和 "cheng.net")合并为一个串:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char * a1 = NULL;
char * a2 = NULL;
a1 = (char*)malloc(10 * sizeof(char));
strcpy(a1, "data.bian");//将字符串"data.bian"复制给a1
a2 = (char*)malloc(10 * sizeof(char));
strcpy(a2, "cheng.net");
int lengthA1 = strlen(a1);//a1串的长度
int lengthA2 = strlen(a2);//a2串的长度
//尝试将合并的串存储在 a1 中,如果 a1 空间不够,则用realloc动态申请
if (lengthA1 < lengthA1 + lengthA2) {
a1 = (char*)realloc(a1, (lengthA1 + lengthA2+1) * sizeof(char));
}
//合并两个串到 a1 中
for (int i = lengthA1; i < lengthA1 + lengthA2; i++) {
a1[i] = a2[i - lengthA1];
}
//串的末尾要添加 \0,避免出错
a1[lengthA1 + lengthA2] = '\0';
printf("%s", a1);
//用完动态数组要立即释放
free(a1);
free(a2);
return 0;
}
程序运行结果:
data.biancheng.net
注意,程序中给 a1 和 a2 赋值时,使用了 strcpy 复制函数。这里不能直接用 a1 ="data.biancheng",程序编译会出错,报错信息为 "没有 malloc 的空间不能 free"。因为 strcpy 函数是将字符串复制到申请的存储空间中,而直接赋值是字符串存储在别的内存空间(本身是一个常量,放在数据区)中,更改了指针 a1 和 a2 的指向,也就是说,之前动态申请的存储空间虽然申请了,结果还没用呢就丢了。
四、串的块链存储结构
串的块链存储,指的是使用链表结构存储字符串。
本节实现串的块链存储使用的是无头节点的单链表。当然根据实际需要,你也可以自行决定所用链表的结构(双链表还是单链表,有无头节点)。
我们知道,单链表中的 "单" 强调的仅仅是链表各个节点只能有一个指针,并没有限制数据域中存储数据的具体个数。因此在设计链表节点的结构时,可以令各节点存储多个数据。
例如,图 1 所示是用链表存储字符串 shujujiegou
,该链表各个节点中可存储 1 个字符:
图 1 各节点仅存储 1 个数据元素的链表
同样,图 2 设置的链表各节点可存储 4 个字符:
图 2 各节点可存储 4 个数据元素的链表
从图 2 可以看到,使用链表存储字符串,其最后一个节点的数据域不一定会被字符串全部占满,对于这种情况,通常会用 '#' 或其他特殊字符(能与字符串区分开就行)将最后一个节点填满。
初学者可能会问,使用块链结构存储字符串时,怎样确定链表中节点存储数据的个数呢?
链表各节点存储数据个数的多少可参考以下几个因素:
- 串的长度和存储空间的大小:若串包含数据量很大,且链表申请的存储空间有限,此时应尽可能的让各节点存储更多的数据,提高空间的利用率(每多一个节点,就要多申请一个指针域的空间);反之,如果串不是特别长,或者存储空间足够,就需要再结合其他因素综合考虑;
- 程序实现的功能:如果实际场景中需要对存储的串做大量的插入或删除操作,则应尽可能减少各节点存储数据的数量;反之,就需要再结合其他因素。
以上两点仅是目前想到影响节点存储数据个数的因素,在实际场景中,还需结合实现环境综合分析。
这里给出一个实现串的块链存储的 C 语言程序,以加深初学者对此字符串存储方式的认识:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define linkNum 3//全局设置链表中节点存储数据的个数
typedef struct Link {
char a[linkNum]; //数据域可存放 linkNum 个数据
struct Link * next; //代表指针域,指向直接后继元素
}link; // nk为节点名,每个节点都是一个 link 结构体
link * initLink(link * head, char * str);
void displayLink(link * head);
int main()
{
link * head = NULL;
head = initLink(head, "data.biancheng.net");
displayLink(head);
return 0;
}
//初始化链表,其中head为头指针,str为存储的字符串
link * initLink(link * head, char * str) {
int length = strlen(str);
//根据字符串的长度,计算出链表中使用节点的个数
int num = length/linkNum;
if (length%linkNum) {
num++;
}
//创建并初始化首元节点
head = (link*)malloc(sizeof(link));
head->next = NULL;
link *temp = head;
//初始化链表
for (int i = 0; i<num; i++)
{
int j = 0;
for (; j<linkNum; j++)
{
if (i*linkNum + j < length) {
temp->a[j] = str[i*linkNum + j];
}
else
temp->a[j] = '#';
}
if (i*linkNum + j < length)
{
link * newlink = (link*)malloc(sizeof(link));
newlink->next = NULL;
temp->next = newlink;
temp = newlink;
}
}
return head;
}
//输出链表
void displayLink(link * head) {
link * temp = head;
while (temp) {
for (int i = 0; i < linkNum; i++) {
printf("%c", temp->a[i]);
}
temp = temp->next;
}
}
程序输出结果为:
data.biancheng.net
相关文章:

数据结构与算法教程,数据结构C语言版教程!(第四部分、字符串,数据结构中的串存储结构)二
第四部分、字符串,数据结构中的串存储结构 串存储结构,也就是存储字符串的数据结构。 很明显,字符串之间的逻辑关系也是“一对一”,用线性表的思维不难想出,串存储结构也有顺序存储和链式存储。 提到字符串ÿ…...

第七在线荣获百灵奖 Buylink Awards 2023零售圈年度卓越服务商品牌
1月11日,由零售圈主办、20零售连锁协会协办、30零售行业媒体支持的中国零售圈大会暨2024未来零售跨年盛典在西安落下帷幕,在这个零售行业盛典中,第七在线凭借其高精尖产品和卓越的服务质量成功入选,并荣获了“百灵奖 Buylink Awar…...

通过myBatis将sql语句返回的值自动包装成一个java对象(3)
1.如果sql字段和java字段名字不一样怎么办? 之前我们将sql返回值转换为java对象时,每条sql的返回值的字段名和java类中的字段名是一一对应的,ie:sql选择的user有username和password两个字段,java中的user对象也有两个…...

基于SSM的驾校信息管理系统设计与实现
末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:Vue、HTML 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目:是…...
矩阵行列式的四大应用
目录 一. 介绍 二. 行列式的基本性质 2.1 单位阵的行列式 2.2 交换行位置的行列式 三. 矩阵求逆与行列式 四. 体积与行列式 五. 矩阵主元与行列式 六. 解方程与矩阵行列式 七. 小结 一. 介绍 行列式可以反应矩阵的很多性质,比如可以求矩阵的逆,…...

【小笔记】时序数据分类算法最新小结
2024.1.15 最近基于时序数据训练分类算法,对其进行了一番了解,主要围绕以下几点: 时序数据算法有哪些细分类?时序数据分类算法经典模型?当下时序分类算法模型强baseline?有没有现成的工具? 1…...

使用Python+pygame实现贪吃蛇小游戏
使用Pythonpygame贪吃蛇小游戏 使用第三方库pygame,关于Python中pygame游戏模块的安装使用可见 https://blog.csdn.net/cnds123/article/details/119514520 给出两种实现。 第一种 运行效果如下: 游戏源码如下: import pygame import sy…...

SpringBoot 全局异常统一处理:BindException(绑定异常)
概述 在Spring Boot应用中,数据绑定是一个至关重要的环节,它负责将HTTP请求中的参数映射到控制器方法的入参对象上。在这个过程中如果遇到任何问题,如参数缺失、类型不匹配或验证失败等,Spring MVC将会抛出一个org.springframewo…...

ucloud轻量云(wordpress)配置ssl
ucloud 轻量云(wordpress)配置ssl 1、上传ssl证书到/usr/local/software/apache/conf,这里的文件名和内容与ucloud控制台下载下来的文件名和内容保持一致 2、修改httpd.conf文件 vim /usr/local/software/apache/conf/httpd.conf 找到下面两行,去掉注…...

电脑/设备网络共享给其他设备上网
文章目录 一、概述二、设置网络共享2.1 电脑可以上网,通过网络共享让其他设备也可以上网2.2 手机如何使用USB数据线共享网络给电脑 一、概述 现在有如下几种情况: 设备本身不能上网,需要通过电脑上网 笔记本WIFI连热点上网,然后…...
vue之虚拟滚动
一、解决的问题 对于大量数据的懒加载,我们可以使用虚拟滚动的技术。虚拟滚动的原理是只渲染可视区域内的数据,当用户滚动时,动态计算并渲染新的可视数据,从而实现大数据量的流畅滚动。 在Vue中,我们可以使用第三方库…...
Redis学习指南(11)-Redis的有序集合数据类型介绍
文章目录 特点和用途常用命令插入操作查询操作删除操作 示例总结 Redis的有序集合数据类型是一种高效的数据结构,能够存储多个成员和对应的分值,并能够根据分值进行快速的查找、插入和删除操作。本文将详细介绍Redis的有序集合数据类型,包括其…...

Spring的纯注解配置
1.环境搭建 1.1.创建工程 1.2.待改造的问题 我们发现,之所以我们现在离不开xml配置文件,是因为我们有一处很关键的配置,如果他要也能用注解配置,那么我们就可以脱离xml文件了: 1.2.1.jdbc配置 <context:propert…...
numpy 筛选多段数据
目录 掩码方式 利用切片 掩码方式 range_to_remove list(range(77-1, 111-1)) list(range(122-1, 135-1))keep_mask np.ones(image0_cut.shape[0], dtypebool)keep_mask[range_to_remove] Falseprocessed_data image0_cut[keep_mask] 利用切片 import numpy as np# 假设…...

【Kotlin】协程的字节码原理
前言 协程是Koltin语言最重要的特性之一,也是最难理解的特性。网上关于kotlin协程的描述也是五花八门,有人说它是轻量级线程,有人说它是无阻塞式挂起,有人说它是一个异步框架等等,众说纷芸。甚至还有人出了书籍专门介…...

区间预测 | Matlab实现LSSVM-ABKDE的最小二乘支持向量机结合自适应带宽核密度估计多变量回归区间预测
区间预测 | Matlab实现LSSVM-ABKDE的最小二乘支持向量机结合自适应带宽核密度估计多变量回归区间预测 目录 区间预测 | Matlab实现LSSVM-ABKDE的最小二乘支持向量机结合自适应带宽核密度估计多变量回归区间预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现…...

基于深度学习的实例分割的Web应用
基于深度学习的实例分割的Web应用 1. 项目简介1.1 模型部署1.2 Web应用 2. Web前端开发3. Web后端开发4. 总结 1. 项目简介 这是一个基于深度学习的实例分割Web应用的项目介绍。该项目使用PaddlePaddle框架,并以PaddleSeg训练的图像分割模型为例。 1.1 模型部署 …...

20240115如何在线识别俄语字幕?
20240115如何在线识别俄语字幕? 2024/1/15 21:25 百度搜索:俄罗斯语 音频 在线识别 字幕 Bilibili:俄语AI字幕识别 音视频转文字 字幕小工具V1.2 BING:音视频转文字 字幕小工具V1.2 https://www.bilibili.com/video/BV1d34y1F7…...

Flink 处理函数(1)—— 基本处理函数
在 Flink 的多层 API中,处理函数是最底层的API,是所有转换算子的一个概括性的表达,可以自定义处理逻辑 在处理函数中,我们直面的就是数据流中最基本的元素:数据事件(event)、状态(st…...

Linux系统下编译MPlayer
一、编译MPlayer 在 http://www.mplayerhq.hu/design7/dload.html 下载MPlayer源码 执行命令: tar -xf MPlayer-1.5.tar.xz cd MPlayer-1.5 ./configure --prefix$(pwd)/install --yasm make make install 然后在install/bin目录下即会生成mplayer的可执行文件 二…...

JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...

初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...