【数据结构】数组和字符串(十三):链式字符串的基本操作(串长统计、查找、复制、插入、删除、串拼接)

文章目录

  • 4.3 字符串
    • 4.3.1 字符串的定义与存储
    • 4.3.2 字符串的基本操作(链式存储)
      • 1. 结构体
      • 2. 初始化
      • 3. 判空
      • 4. 串尾添加
      • 5. 打印
      • 6. 串长统计
      • 7. 查找
      • 8. 复制
      • 9. 插入
      • 10. 删除
      • 11. 串拼接
      • 12. 销毁
      • 13. 主函数
      • 14. 代码整合

4.3 字符串

  字符串(String)是由零个或多个字符(char)顺序排列组成的有限序列,简称为串。例如 “good morning”就是由12个字符构成的一个字符串。一般把字符串记作:

S = ′ ′ a 0 a 1 … a n − 1 ′ ′ S=''a_{0} a_{1}…a_{n-1}'' S=′′a0a1an1′′

  其中S是串名,引号中的字符序列是串值。字符个数是串的长度,长度为0的串被称为空串,因为它不包含任何字符。需要注意的是,空格字符(" ")并不是空串,因为它包含一个字符——空格。
  若把某个串称为主串,则主串中任意个连续的字符组成的子序列被称为子串。子串在主串中第一次出现时,其首字符在主串中的序号被称为该子串在主串中的位置。
  关于字符串的基础知识亦可参考前文:
【重拾C语言】六、批量数据组织(三)数组初值;字符串、字符数组、字符串数组;类型定义 typedef
【重拾C语言】七、指针(三)指针与字符串(字符串与字符串数组;指针与字符串的遍历、拷贝、比较;反转字符串

4.3.1 字符串的定义与存储

  字符串在许多非数值计算问题中扮演着重要的角色,并在模式匹配、程序编译和数据处理等领域得到广泛应用。在高级程序设计语言中,字符串通常被定义为以特殊字符’\0’(称为空字符或字符串结束符)结尾的字符序列。这个约定使得在处理字符串时可以方便地确定字符串的结束位置。关于字符串的存储方式,主要有两种常见的方式:

  • 顺序存储:字符串的字符按照顺序依次存储在连续的内存空间中。这种方式使得字符串的访问和操作效率较高,可以通过索引直接访问任意位置的字符。在顺序存储方式中,字符串的长度可以通过计算字符个数或者遇到’\0’结束符来确定。

  • 链式存储:字符串的字符通过链表的方式进行存储。每个节点包含一个字符和指向下一个节点的指针。链式存储方式可以动态地分配内存,适用于长度可变的字符串。但是相比于顺序存储,链式存储方式需要更多的内存空间,并且访问字符需要遍历链表。

  选择何种存储方式取决于具体的应用场景和需求。顺序存储适合于需要频繁访问和操作字符串的情况,而链式存储适合于长度可变的字符串或者对内存空间要求较高的情况。具体C语言实现可参照前文:
  【数据结构】数组和字符串(十一):字符串的定义与存储(顺序存储、链式存储及其C语言实现)

4.3.2 字符串的基本操作(链式存储)

  • 串长统计返回串s的长度;
  • 串定位返回字符或子串在母串s中首次出现的位置的指针;
  • 串复制将一个串s2复制到另一个串s1中;
  • 串插入在指定位置后面插入字符串;
  • 串删除是删除一个子串;
  • 串拼接将串s2拼接到串s1的尾部;
  • ……

  【数据结构】线性表(二)单链表及其基本操作(创建、插入、删除、修改、遍历打印)

1. 结构体

typedef struct Node {char data;struct Node* next;
} Node;typedef struct {Node* head;Node* tail;
} LinkedList;
  • Node:表示链表的节点,包含一个字符数据和一个指向下一个节点的指针。
  • LinkedList:表示链表,包含链表的头节点和尾节点。

2. 初始化

  initLinkedList函数:用于初始化链表,将头节点和尾节点都设置为NULL

void initLinkedList(LinkedList* list) {list->head = NULL;list->tail = NULL;
}

3. 判空

  isEmpty函数:判断链表是否为空,即头节点是否为NULL

bool isEmpty(const LinkedList* list) {return list->head == NULL;
}

4. 串尾添加

   append函数:向链表末尾添加一个字符节点。

void append(LinkedList* list, char data) {Node* newNode = (Node*)malloc(sizeof(Node));newNode->data = data;newNode->next = NULL;if (isEmpty(list)) {list->head = newNode;list->tail = newNode;} else {list->tail->next = newNode;list->tail = newNode;}
}
  • 如果链表为空,即头节点为NULL,则将新节点设置为头节点和尾节点。
  • 如果链表不为空,即头节点不为NULL,则将新节点链接到尾节点的后面,并将尾节点更新为新节点。

5. 打印

   display函数:遍历链表并打印出所有字符节点的数据。

void display(const LinkedList* list) {Node* current = list->head;while (current != NULL) {printf("%c", current->data);current = current->next;}printf("\n");
}
  • 函数接受一个指向LinkedList结构体的指针作为参数,然后从头节点开始遍历链表,打印每个节点的数据。

6. 串长统计

   length函数:计算链表的长度,即字符节点的个数。

int length(const LinkedList* list) {int count = 0;Node* current = list->head;while (current != NULL) {count++;current = current->next;}return count;
}
  • 函数接受一个指向LinkedList结构体的指针作为参数,然后从头节点开始遍历链表,每遍历一个节点,计数器加1,最后返回计数器的值。

7. 查找

   search函数:在链表中搜索目标字符串。

int search(const LinkedList* list, const char* target) {int targetLength = strlen(target);int listLength = length(list);if (targetLength > listLength) {printf("Error: Target string is longer than the source string.\n");return -1;}Node* current = list->head;int index = 0;while (current != NULL) {if (current->data == target[0]) {Node* temp = current;int i = 0;while (temp != NULL && temp->data == target[i]) {temp = temp->next;i++;if (i == targetLength) {return index;}}}current = current->next;index++;}printf("Error: Target string not found in the source string.\n");return -1;
}
  • 首先比较目标字符串的长度和链表的长度,如果目标字符串比链表长,说明无法找到目标字符串,函数返回错误。
  • 然后从头节点开始遍历链表,找到第一个与目标字符串首字符相同的节点,
    • 然后从该节点开始逐个比较字符,直到找到完全匹配的目标字符串或链表遍历结束。
    • 如果找到目标字符串,函数返回目标字符串在链表中的起始位置的索引;
    • 如果未找到目标字符串,函数返回错误。

8. 复制

  copy函数:将源链表中的字符复制到目标链表中。

bool copy(LinkedList* dest, const LinkedList* src) {Node* current = src->head;while (current != NULL) {append(dest, current->data);current = current->next;}return true;
}
  • 函数接受两个指向LinkedList结构体的指针,分别表示源链表和目标链表。
  • 通过遍历源链表的每个节点,创建一个新节点并将数据复制过去,然后将新节点添加到目标链表的末尾。

9. 插入

   insert函数:在链表的指定位置插入一个字符串。

bool insert(LinkedList* list, const char* insertStr, int pos) {int listLength = length(list);int insertStrLength = strlen(insertStr);if (pos < 0 || pos > listLength) {printf("Error: Invalid insertion position.\n");return false;}Node* current = list->head;int index = 0;while (current != NULL) {if (index == pos) {for (int i = 0; i < insertStrLength; i++) {Node* newNode = (Node*)malloc(sizeof(Node));newNode->data = insertStr[i];newNode->next = current->next;current->next = newNode;current = newNode;}return true;}current = current->next;index++;}return false;
}
  • 首先判断插入位置是否合法,即索引是否在有效范围内。然后遍历链表找到插入位置的节点,然后逐个创建新节点并插入到链表中。

10. 删除

  delete函数:从链表中删除指定位置和长度的字符。

bool delete(LinkedList* list, int pos, int len) {int listLength = length(list);if (pos < 0 || pos >= listLength) {printf("Error: Invalid deletion position.\n");return false;}if (pos + len > listLength) {printf("Error: Deletion length exceeds the length of the string.\n");return false;}Node* current = list->head;int index = 0;while (current != NULL) {if (index == pos) {Node* prev = current;Node* temp = current;for (int i = 0; i < len; i++) {temp = temp->next;free(prev);prev = temp;}current->next = temp;return true;}current = current->next;index++;}return false;
}
  • 首先判断删除位置是否合法,然后找到删除位置的节点,逐个删除指定长度的节点。

11. 串拼接

  concat函数:将第二个链表中的字符追加到第一个链表的末尾。的末尾。

bool concat(LinkedList* list1, const LinkedList* list2) {Node* current = list2->head;while (current != NULL) {append(list1, current->data);current = current->next;}return true;
}
  • 遍历第二个链表的每个节点,将节点的数据追加到第一个链表。

12. 销毁

  destroy函数:释放链表占用的内存。遍历链表的每个节点,释放节点的内存,并将头节点和尾节点设置为NULL

void destroy(LinkedList* list) {Node* current = list->head;while (current != NULL) {Node* temp = current;current = current->next;free(temp);}list->head = NULL;list->tail = NULL;
}
  • 函数遍历链表的每个节点,释放节点的内存,并将头节点和尾节点设置为NULL

13. 主函数


int main() {LinkedList S;initLinkedList(&S);const char target[] = "H";LinkedList copyStr;initLinkedList(&copyStr);const char insertStr[] = "H";int pos = 3;append(&S, 'q');append(&S, 'o');append(&S, 'm');append(&S, 'o');append(&S, 'l');append(&S, 'a');append(&S, 'n');append(&S, 'g');append(&S, 'm');append(&S, 'a');display(&S);int searchIndex = search(&S, target);if (searchIndex != -1) {printf("Target string found at index: %d\n", searchIndex);}copy(&copyStr, &S);display(&copyStr);insert(&S, insertStr, pos);display(&S);delete(&S, pos, strlen(insertStr));display(&S);concat(&S, &copyStr);display(&S);destroy(&S);destroy(&copyStr);return 0;
}

在这里插入图片描述

14. 代码整合

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>typedef struct Node {char data;struct Node* next;
} Node;typedef struct {Node* head;Node* tail;
} LinkedList;void initLinkedList(LinkedList* list) {list->head = NULL;list->tail = NULL;
}bool isEmpty(const LinkedList* list) {return list->head == NULL;
}void append(LinkedList* list, char data) {Node* newNode = (Node*)malloc(sizeof(Node));newNode->data = data;newNode->next = NULL;if (isEmpty(list)) {list->head = newNode;list->tail = newNode;} else {list->tail->next = newNode;list->tail = newNode;}
}void display(const LinkedList* list) {Node* current = list->head;while (current != NULL) {printf("%c", current->data);current = current->next;}printf("\n");
}int length(const LinkedList* list) {int count = 0;Node* current = list->head;while (current != NULL) {count++;current = current->next;}return count;
}int search(const LinkedList* list, const char* target) {int targetLength = strlen(target);int listLength = length(list);if (targetLength > listLength) {printf("Error: Target string is longer than the source string.\n");return -1;}Node* current = list->head;int index = 0;while (current != NULL) {if (current->data == target[0]) {Node* temp = current;int i = 0;while (temp != NULL && temp->data == target[i]) {temp = temp->next;i++;if (i == targetLength) {return index;}}}current = current->next;index++;}printf("Error: Target string not found in the source string.\n");return -1;
}bool copy(LinkedList* dest, const LinkedList* src) {Node* current = src->head;while (current != NULL) {append(dest, current->data);current = current->next;}return true;
}bool insert(LinkedList* list, const char* insertStr, int pos) {int listLength = length(list);int insertStrLength = strlen(insertStr);if (pos < 0 || pos > listLength) {printf("Error: Invalid insertion position.\n");return false;}Node* current = list->head;int index = 0;while (current != NULL) {if (index == pos) {for (int i = 0; i < insertStrLength; i++) {Node* newNode = (Node*)malloc(sizeof(Node));newNode->data = insertStr[i];newNode->next = current->next;current->next = newNode;current = newNode;}return true;}current = current->next;index++;}return false;
}bool delete(LinkedList* list, int pos, int len) {int listLength = length(list);if (pos < 0 || pos >= listLength) {printf("Error: Invalid deletion position.\n");return false;}if (pos + len > listLength) {printf("Error: Deletion length exceeds the length of the string.\n");return false;}Node* current = list->head;int index = 0;while (current != NULL) {if (index == pos) {Node* prev = current;Node* temp = current;for (int i = 0; i < len; i++) {temp = temp->next;free(prev);prev = temp;}current->next = temp;return true;}current = current->next;index++;}return false;
}bool concat(LinkedList* list1, const LinkedList* list2) {Node* current = list2->head;while (current != NULL) {append(list1, current->data);current = current->next;}return true;
}void destroy(LinkedList* list) {Node* current = list->head;while (current != NULL) {Node* temp = current;current = current->next;free(temp);}list->head = NULL;list->tail = NULL;
}int main() {LinkedList S;initLinkedList(&S);const char target[] = "H";LinkedList copyStr;initLinkedList(&copyStr);const char insertStr[] = "H";int pos = 3;append(&S, 'q');append(&S, 'o');append(&S, 'm');append(&S, 'o');append(&S, 'l');append(&S, 'a');append(&S, 'n');append(&S, 'g');append(&S, 'm');append(&S, 'a');display(&S);int searchIndex = search(&S, target);if (searchIndex != -1) {printf("Target string found at index: %d\n", searchIndex);}copy(&copyStr, &S);display(&copyStr);insert(&S, insertStr, pos);display(&S);delete(&S, pos, strlen(insertStr));display(&S);concat(&S, &copyStr);display(&S);destroy(&S);destroy(&copyStr);return 0;
}

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

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

相关文章

Latex排版SIGGRAPH总结(持续总结中...)

本文学习总结自&#xff1a;How to use the ACM SIGGRAPH / TOG LaTeX template 相关文件&#xff1a;百度网盘 首先解压 “my paper” 中的文件&#xff0c;并用Latex打开mypaper.tex. 多行连等公式 \begin{equation}表示编号公式&#xff0c;\[ \]表示无编号公式 无编号\b…

双轮差速模型机器人通过线速度、角速度计算机器人位姿

已知上一时刻机器人位置P_OLD (x,y,),机器人当前时刻的线速度和角速度&#xff08;v,&#xff09;,短时间内t内&#xff0c;机器人在线性部分和非线性部分的增量为 线性部分&#xff1a; 非线性部分&#xff1a; 由于可能非常小&#xff0c;导致非线性部分数值不稳定&#xf…

【R统计】各式各样的插补法解决数据缺失的问题!

&#x1f482; 个人信息&#xff1a;酷在前行&#x1f44d; 版权: 博文由【酷在前行】原创、需要转载请联系博主&#x1f440; 如果博文对您有帮助&#xff0c;欢迎点赞、关注、收藏 订阅专栏&#x1f516; 本文收录于【R统计】&#xff0c;该专栏主要介绍R语言实现统计分析的…

【计算机视觉】对极几何

文章目录 一、极线约束&#xff08;Epipolar Constraint&#xff09;二、相机标定过的情况三、相机没有标定过的情况四、八点算法&#xff08;eight-point algorithm&#xff09; 我的《计算机视觉》系列参考UC Berkeley的CS180课程&#xff0c;PPT可以在课程主页看到。 在上一…

关于preempt count的疑问

Linux中的preempt_count - 知乎 https://www.cnblogs.com/hellokitty2/p/15652312.html LWN&#xff1a;关于preempt_count()的四个小讨论&#xff01;-CSDN博客 主要是参考这些文章 之前一直认为只要是in_interrupt()返回非0值&#xff0c;那么就可以认为当前在中断上下文。即…

阿昌教你如何优雅的数据脱敏

阿昌教你如何优雅的数据脱敏 Hi&#xff0c;我是阿昌&#xff0c;最近有一个数据脱敏的需求&#xff0c;要求用户可自定义配置数据权限&#xff0c;并对某种类型数据进行脱敏返回给前端 一、涉及知识点 SpringMVCJava反射Java自定义注解Java枚举 二、方案选择 1、需求要求…

Webpack打包图片-js-vue

文章目录 一、Webpack打包图片1.加载图片资源的准备2.认识asset module type3.asset module type的使用4.url-loader的limit效果 二、babel1.为什么需要babel2.babel命令行的使用3.babel插件的使用4.babel的预设preset5.babel-loader6.babel-preset 三、加载Vue文件1.编写App.v…

使用Ansible中的playbook

目录 1.Playbook的功能 2.YAML 3.YAML列表 4.YAML的字典 5.playbook执行命令 6.playbook的核心组件 7.vim 设定技巧 示例 1.Playbook的功能 playbook 是由一个或多个play组成的列表 Playboot 文件使用YAML来写的 2.YAML #简介# 是一种表达资料序列的格式,类似XML #特…

开关电源测试过压保护的测试标准及其方法

过压保护的原理 过压保护是电压超过预定值时降低电压的一种方式&#xff0c;原理是通过电路中的电压检测电路来检测电路中的电压是否超过了设定的阈值&#xff0c;如果超过了阈值&#xff0c;就会触发过压保护器件&#xff0c;使电源断开或使受控设备电压降低&#xff0c;保护电…

网络协议--TCP的交互数据流

19.1 引言 前一章我们介绍了TCP连接的建立与释放&#xff0c;现在来介绍使用TCP进行数据传输的有关问题。 一些有关TCP通信量的研究如[Caceres et al. 1991]发现&#xff0c;如果按照分组数量计算&#xff0c;约有一半的TCP报文段包含成块数据&#xff08;如FTP、电子邮件和U…

使用Fiddler进行Mock测试

1、接口抓包 找到要mock的接口&#xff0c;打开fiddler抓包 以某某接口为例&#xff0c;找到下面的接口 http://XXX/SYSTEMS 2、复制该接口数据到本地 在接口上进行右键点击&#xff0c;选择save -> …and Open as Local File -> 默认会保存至桌面&#xff0c;示例中的数…

uniapp的启动页、开屏广告

uniapp的启动页、开屏广告 启动页配置广告开屏 启动页配置 在manifest.json文件中找到APP启动界面配置&#xff0c;可以看到有Android和iOS的启动页面的配置 &#xff0c;选择自定义启动图即可配置 广告开屏 在pages中新建一个广告开屏文件并在pases.json的最顶部配置这个页…

开发商城系统的一些小建议

电子商务的迅猛发展&#xff0c;商城系统已经成为了企业推广产品和服务、吸引更多消费者的重要工具。然而&#xff0c;要想在竞争激烈的市场中脱颖而出&#xff0c;提升用户体验成为了至关重要的一环。下面就商城系统的开发作一些简单分享&#xff0c;以帮助企业更好地满足用户…

跨国文件传输为什么要用专业的大文件传输软件?

跨国文件传输是许多跨国企业需要的基础工作&#xff0c;对于传输的质量和速度要求也是很严格的&#xff0c;随着数据量的不断增加&#xff0c;寻常传统的传输方式肯定是不行&#xff0c;需要新的技术和方式来进行传输&#xff0c;大文件传输软件应运而出&#xff0c;那它有什么…

联想百应:构建“生态资源池”,打造中小企业转型第一服务平台

与3800多家服务商和100多家SaaS生态伙伴携手&#xff0c;累计支持超过20万中小企业智能化转型……在近日由工业和信息化部和安徽省举办的2023全国中小企业数字化转型大会上&#xff0c;联想集团首次公布供应链、平台、技术、生态与绿色赋能五大赋能能力和助力中小企业“链式”成…

sqlite3 关系型数据库语言 SQL 语言

SQL(Structured Query Language)语言是一种结构化查询语言,是一个通用的,功能强大的关系型数据库操作语言. 包含 6 个部分: 1.数据查询语言(DQL:Data Query Language) 从数据库的二维表格中查询数据,保留字 SELECT 是 DQL 中用的最多的语句 2.数据操作语言(DML) 最主要的关…

神经网络的解释方法之CAM、Grad-CAM、Grad-CAM++、LayerCAM

原理优点缺点GAP将多维特征映射降维为一个固定长度的特征向量①减少了模型的参数量&#xff1b;②保留更多的空间位置信息&#xff1b;③可并行计算&#xff0c;计算效率高&#xff1b;④具有一定程度的不变性①可能导致信息的损失&#xff1b;②忽略不同尺度的空间信息CAM利用…

前端 :用HTML , CSS ,JS 做一个秒表

1.HTML&#xff1a; <body><div id "content"><div id "top"><div id"time">00:00:000</div></div><div id "bottom"><div id "btn_start">开始</div><div …

04.Oracle的体系架构

Oracle的体系架构 一、主要组件 一、主要组件 下面是一张网图&#xff0c;大家可以了解一下oracle的体系架构 Oracle数据库的体系架构可以分为以下几个主要组件&#xff1a;实例&#xff08;Instance&#xff09;、数据库&#xff08;Database&#xff09;、表空间&#xff…

瑞数专题五

今日文案&#xff1a;焦虑&#xff0c;想象力过度发酵的产物。 网址&#xff1a;https://www.iyiou.com/ 专题五主要是分享瑞数6代。6代很少见&#xff0c;所以找理想哥要的&#xff0c;感谢感谢。 关于瑞数作者之前已经分享过4篇文章&#xff0c;全都收录在瑞数专栏中了&am…