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

news2024/11/19 19:24:21

文章目录

  • 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.coloradmin.cn/o/1155076.html

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

相关文章

CodeGeeX:对标GitHub Copilot,国产免费可用的代码补全助手

大家好&#xff0c;我是豆小匠。 本期介绍的插件CodeGeeX&#xff0c;是一款免费的智能编程助手。 主要功能是代码生成和补全&#xff0c;但不止于此&#xff01; CodeGeeX介绍 CodeGeeX是清华大学和智谱AI联合打造的多语言代码生成模型。 第一代是完全在华为昇腾芯片平台训练…

华为OD机考算法题:生日礼物

题目部分 题目生日礼物难度易题目说明小牛的孩子生日快要到了&#xff0c;他打算给孩子买蛋糕和小礼物&#xff0c;蛋糕和小礼物各买一个&#xff0c;他的预算不超过x元。蛋糕 cake 和小礼物 gift 都有多种价位的可供选择。输入描述第一行表示cake的单价&#xff0c;以逗号分隔…

③ 软件工程CMM、CMMI模型【软考中级-软件设计师 考点】

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ ③ 软件工程CMM、CMMI模型【软考中级-软件设计…

SpringCloud Alibaba Demo(Nacos,OpenFeign,Gatway,Sentinel)

开源地址&#xff1a; ma/springcloud-alibaba-demo 简介 参考&#xff1a;https://www.cnblogs.com/zys2019/p/12682628.html SpringBoot、SpringCloud 、SpringCloud Alibaba 以及各种组件存在版本对应关系。可参考下面 版本对应 项目前期准备 启动nacos. ./startup.c…

营收净利双降、股价下跌四成,敷尔佳带伤闯关“双11”

今年双11预售已经开启&#xff0c;敷尔佳在天猫、抖音等电商平台火热营销&#xff1b;营销热业绩冷&#xff0c;敷尔佳的三季报不及预期。 10月23日&#xff0c;哈尔滨敷尔佳科技发展有限公司(下称“敷尔佳”&#xff0c;301371SZ)公布2023年三季报&#xff0c;其三季度营收净…

【C++ 系列文章 -- 程序员考试 下午场 C++ 专题 201805 】

文章目录 1.1 C 题目六1.1.1 填空&#xff08;1&#xff09;详解1.1.1.1 C 纯虚函数介绍 1.1.2 填空&#xff08;2&#xff09;详解1.1.2.1 父类声明了带参构造函数1.1.2.2 子类中构造函数的构造原则 1.1.3 填空&#xff08;3&#xff09;详解1.1.4 填空&#xff08;4&#xff…

Python小试牛刀:GUI(图形界面)实现计算器界面

Python GUI 是指 Python 图形用户界面库&#xff0c;它们可以帮助开发者创建在计算机上运行的图形用户界面&#xff08;GUI&#xff09;。下面是一些常用的 Python GUI 库&#xff1a; Tkinter&#xff1a; Tkinter 是 Python 的标准 GUI 库&#xff0c;它是一个开源的、跨平台…

LeetCode刷题之 存在重复元素(题目分析➕源代码)

题目链接&#x1f517;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 1. 题目分析 本题是要找到数组中的重复元素&#xff0c;所以我们分析出一下几点&#xff1a; 1. bool是一种数据类型&#xff0c;true是非0值&#xff0c;false是0.。 2. 数组…

绘制教材P68页产品的层次方框图。

层次方框图&#xff1a; 用树形结构的一系列多层次的矩形框绘制数据的层次结构&#xff0c;树形结构的顶层是一个单独的矩形框&#xff0c;它代表完整的数据结构&#xff0c;下面的各层矩形框代表这个数据的子集&#xff0c;最底层的各个框代表组成这个数据的实际数据元素&…

verilog语言学习

1. 时延 2. 一位全加器设计&#xff1a;三种建模方式 实际的设计中往往是这三种设计模式的混合 3. 4. 5. 6. 7. 建立模型时信号的连接&#xff08;重点&#xff09; 8. initial语句 9. always语句 在always中不能同时判断同一个信号的上升沿&#xff08;posedge&#xff0…

网工内推 | IDC网工、运维,上市公司,主流厂商认证优先,六险一金

01 软通动力 招聘岗位&#xff1a;ICD机房运维工程师 职责描述&#xff1a; 1.维护及管理数据中心内各类服务器及网络设备。 2.处理数据中心各类服务器和网络相关故障和告警。 3.负责数据中心内项目交付管理&#xff0c;包括LLD评审、硬装工艺验收、ASP施工管理等。 4.负责数据…

什么是互动广告

随着数字技术的迅速发展和消费者行为的转变&#xff0c;互动广告已成为现代广告行业的重要组成部分。互动广告以其独特的优势和形式&#xff0c;不断刷新人们对广告的认知&#xff0c;为广告行业带来新的机遇和挑战&#xff0c;那么就来一起了解互动广告吧。 一、互动广告的定义…

笔记49:53语言模型--课程笔记

本地笔记地址&#xff1a;D:\work_file\DeepLearning_Learning\03_个人笔记\3.循环神经网络\语言模型 PS&#xff1a;沐神别怪我&#xff0c;实在是截屏避不开啊&#xff0c;我就留个备忘&#xff0c;在我博客里先委屈一下哈&#xff0c;对不住了 a a a a a a a a a a…

二十一、Arcpy批量镶嵌——结合Landsat数据提取城市建成区

一、前言 前文介绍Pycharm软件安装和激活,以及运行环境的设置,本文就详细介绍一下几何Landsat数据有哪些步骤可以通过Arcpy代码来实现批量操作,其实主要集中在Landsat数据预处理过程中,包括数据镶嵌、裁剪、去背景、重采样以及波段组合计算、NDVI、NDBI计算,在一定程度上…

JetBrains TeamCity远程命令执行漏洞

一、免责声明&#xff1a; 本次文章仅限个人学习使用&#xff0c;如有非法用途均与作者无关&#xff0c;且行且珍惜&#xff1b;由于传播、利用本公众号所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;公众号望雪阁及作者不为此承…

EPLAN连接编号的问题

连接编号的问题 1.连接编号的目的 连接编号也就是常说的编线号.编线号的目的是为了在现场装配,调试,检修的时候,方便查线.使真实的接线与原理图能够方便地对应. 2.标准对连接编号的规定 标准中规定了导线应该编线号,但是没有说一定要使用什么样的规则.我觉得保证正常使用的前提…

YOLOv8改进: AIFI (尺度内特征交互)助力YOLO | YOLO终结者?RT-DETR一探究竟

💡💡💡本文全网首发独家改进: AIFI (尺度内特征交互)助力YOLO ,提升尺度内和尺度间特征交互能力,同时降低多个尺度的特征之间进行注意力运算,计算消耗较大等问题 推荐指数:五星 AIFI | 亲测在多个数据集能够实现涨点 💡💡💡Yolov8魔术师,独家首发创新(…

unordered系列关联式容器--哈希结构详细讲解及使用示例

目录 unordered系列关联式容器unordered_map 哈希哈希概念哈希函数直接定址法&#xff1a;除留余数法&#xff1a; 哈希冲突解决哈希冲突闭散列&#xff1a;开散列&#xff1a; unordered系列关联式容器 之前讲解在C98中STL提供了底层为红黑树结构的一系列关联式容器&#xff…

基于动物迁徙算法的无人机航迹规划-附代码

基于动物迁徙算法的无人机航迹规划 文章目录 基于动物迁徙算法的无人机航迹规划1.动物迁徙搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用动物迁徙算法来优化无人机航迹规划。 …