数据结构 串

news2024/9/22 15:35:42

在这里插入图片描述

术语概念

在数据结构中,串(String)是由零个或多个字符组成的有限序列。它是一种常见的数据类型,常用于表示文本、字符串和符号序列等信息。串可以包含任意字符,包括字母、数字、符号以及空格等。

主串(Main String)是指一个串中的完整序列,它可以包含一个或多个字串。主串是整个串的基础,在处理串的问题时,通常会对主串进行操作。

字串(Substring)是指主串中连续的一段字符序列。换句话说,字串是主串的一部分,它由主串中的一个或多个字符按照顺序组成。字串可以包含主串中的所有字符,也可以只包含其中的一部分。

串长(Length of a String)是指串中字符的数量,也就是串的长度。它表示了一个串中字符的个数,可以用来衡量串的大小。常用的方法是使用一个整数来表示串的长度。

在计算机科学中,对串的操作和处理是非常常见的,比如搜索、匹配、替换、排序等。理解主串、字串和串长的概念有助于进行字符串处理和相关算法的设计与实现。

存储结构

在这里插入图片描述

串的存储结构有多种方式,其中包括定长顺序存储、堆分配存储和块链存储。

  1. 定长顺序存储(Fixed-Length Sequential Storage):在定长顺序存储中,串的字符被连续地存储在一块连续的存储区域中,如数组。串的长度在创建时被确定,存储空间被分配给每个字符,且长度不可变。这种存储结构适用于已知长度的串,能够快速访问和操作,但可能会浪费存储空间。

对于定长顺序存储的示例,使用C语言的代码如下:

#include <stdio.h>

int main() {
    char str[11] = "Hello World";

    printf("The string is: %s\n", str);

    return 0;
}

  1. 堆分配存储(Heap Allocation Storage):堆分配存储通过动态内存分配来存储串。在堆分配存储中,使用指针来引用字符序列,而不需要预先确定存储空间大小。这种存储结构适用于长度可变的串,可以根据需要动态分配和释放存储空间,但需要额外的内存管理开销。
    实例:假设我们需要处理一个长度可变的串,用户输入的长度不确定。可以使用堆分配存储,通过动态内存分配来存储字符串。
#include <stdio.h>
#include <stdlib.h>

int main() {
    int length;
    printf("Enter the length of the string: ");
    scanf("%d", &length);

    // 动态分配存储空间
    char* str = (char*)malloc((length + 1) * sizeof(char));

    printf("Enter the string: ");
    scanf("%s", str);

    printf("The string is: %s\n", str);

    // 释放内存
    free(str);
    return 0;
}

  1. 块链存储(Linked Storage):块链存储使用链表数据结构来表示串。每个节点包含一个字符和一个指向下一个节点的指针。块链存储可以动态地增加和删除字符,适用于频繁的插入和删除操作。然而,块链存储对于访问和搜索操作可能不如定长顺序存储和堆分配存储高效。
    实例:假设我们要存储一个字符串"Hello World",可以使用块链存储,每个节点包含一个字符和一个指向下一个节点的指针。
#include <stdio.h>
#include <stdlib.h>

struct Node {
    char data;
    struct Node* next;
};

struct Node* create_linked_string() {
    struct Node* node1 = (struct Node*)malloc(sizeof(struct Node));
    struct Node* node2 = (struct Node*)malloc(sizeof(struct Node));
    struct Node* node3 = (struct Node*)malloc(sizeof(struct Node));
    struct Node* node4 = (struct Node*)malloc(sizeof(struct Node));
    struct Node* node5 = (struct Node*)malloc(sizeof(struct Node));
    struct Node* node6 = (struct Node*)malloc(sizeof(struct Node));
    struct Node* node7 = (struct Node*)malloc(sizeof(struct Node));
    struct Node* node8 = (struct Node*)malloc(sizeof(struct Node));
    struct Node* node9 = (struct Node*)malloc(sizeof(struct Node));
    struct Node* node10 = (struct Node*)malloc(sizeof(struct Node));
    struct Node* node11 = (struct Node*)malloc(sizeof(struct Node));

    // 设置节点的数据
    node1->data = 'H';
    node2->data = 'e';
    node3->data = 'l';
    node4->data = 'l';
    node5->data = 'o';
    node6->data = ' ';
    node7->data = 'W';
    node8->data = 'o';
    node9->data = 'r';
    node10->data = 'l';
    node11->data = 'd';

    // 构建链表
    node1->next = node2;
    node2->next = node3;
    node3->next = node4;
    node4->next = node5;
    node5->next = node6;
    node6->next = node7;
    node7->next = node8;
    node8->next = node9;
    node9->next = node10;
    node10->next = node11;
    node11->next = NULL;

    return node1;
}

int main() {
    // 创建块链存储的串
    struct Node* head = create_linked_string();

    // 遍历打印串
    struct Node* current = head;
    while (current != NULL) {
        printf("%c", current->data);
        current = current->next;
    }

    // 释放内存
    current = head;
    while (current != NULL) {
        struct Node* temp = current;
        current = current->next;
        free(temp);
    }

    return 0;
}

在上述代码中,我们定义了一个结构体 Node,包含一个字符数据 data 和一个指向下一个节点的指针 next。然后,我们通过动态内存分配来创建每个节点,并设置节点的数据。接下来,我们使用指针将节点连接起来,形成一个链表。最后,我们遍历链表打印出字符序列,并释放动态分配的内存。

选择合适的存储结构取决于串的特性和操作需求。如果串的长度已知且固定,则定长顺序存储是一个简单且高效的选择。如果串的长度可变且需要频繁的插入和删除操作,则堆分配存储或块链存储可能更合适。

模式匹配算法

在这里插入图片描述

暴力匹配法

暴力匹配法(Brute Force Algorithm):

概念:暴力匹配法是一种简单直观的模式匹配算法。它的基本思想是从文本串的第一个字符开始,逐个与模式串的字符进行比较。如果字符相匹配,则继续比较下一个字符,如果不匹配,则将文本串的指针回溯到上一次比较的位置的下一个字符,再重新开始比较。
使用:暴力匹配法的实现相对简单,通过两层循环遍历文本串和模式串进行逐个字符的比较。
实例(C语言):

#include <stdio.h>
#include <string.h>

int bruteForce(char* text, char* pattern) {
    int textLen = strlen(text);
    int patternLen = strlen(pattern);

    for (int i = 0; i <= textLen - patternLen; i++) {
        int j;
        for (j = 0; j < patternLen; j++) {
            if (text[i + j] != pattern[j])
                break;
        }
        if (j == patternLen)
            return i;  // 匹配成功,返回起始位置
    }

    return -1;  // 匹配失败,返回-1
}

int main() {
    char text[] = "ABCABABCDABABCABAB";
    char pattern[] = "ABABCABAB";

    int result = bruteForce(text, pattern);

    if (result == -1)
        printf("Pattern not found in the text\n");
    else
        printf("Pattern found at position: %d\n", result);

    return 0;
}

KMP算法

概念:KMP算法是一种高效的模式匹配算法,它利用了模式串自身的信息来避免无效的比较。KMP算法通过构建一个部分匹配表(即next数组),用于记录模式串中每个位置的最长公共前缀后缀的长度,从而在匹配过程中跳过一些无需比较的字符。
使用:KMP算法的实现分为两个阶段,首先构建部分匹配表(next数组),然后利用该表进行匹配。
实例(C语言):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void buildNext(char* pattern, int* next) {
    int len = strlen(pattern);
    next[0] = -1;
    int i = 0, j = -1;

    while (i < len) {
        if (j == -1 || pattern[i] == pattern[j]) {
            i++;
            j++;
            next[i] = j;
        } else {
            j = next[j];
        }
    }
}

int kmp(char* text, char* pattern) {
    int textLen = strlen(text);
    int patternLen = strlen(pattern);
    int* next = (int*)malloc((patternLen + 1) * sizeof(int));
    buildNext(pattern, next);

    int i = 0, j = 0;

    while (i < textLen && j < patternLen) {
        if (j == -1 || text[i] == pattern[j]) {
            i++;
            j++;
        } else {
            j = next[j];
        }
    }

    free(next);

    if (j == patternLen)
        return i - j;  // 匹配成功,返回起始位置

    return -1;  // 匹配失败,返回-1
}

int main() {
    char text[] = "ABCABABCDABABCABAB";
    char pattern[] = "ABABCABAB";

    int result = kmp(text, pattern);

    if (result == -1)
        printf("Pattern not found in the text\n");
    else
        printf("Pattern found at position: %d\n", result);

    return 0;
}

KMP算法的进一步改进—nextval数组

概念:nextval数组是对KMP算法的一种改进,它进一步减少了模式串与文本串的比较次数。nextval数组在构建过程中,根据模式串的特点,对部分匹配表的构建进行了优化。
使用:使用方法与KMP算法类似,只是在构建部分匹配表时,需要使用nextval数组的构建规则。
实例(C语言):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void buildNextval(char* pattern, int* nextval) {
    int len = strlen(pattern);
    nextval[0] = -1;
    int i = 0, j = -1;

    while (i < len) {
        if (j == -1 || pattern[i] == pattern[j]) {
            i++;
            j++;
            if (pattern[i] != pattern[j])
                nextval[i] = j;
            else
                nextval[i] = nextval[j];
        } else {
            j = nextval[j];
        }
    }
}

int kmpWithNextval(char* text, char* pattern) {
    int textLen = strlen(text);
    int patternLen = strlen(pattern);
    int* nextval = (int*)malloc((patternLen + 1) * sizeof(int));
    buildNextval(pattern, nextval);

    int i = 0, j = 0;

    while (i < textLen && j < patternLen) {
        if (j == -1 || text[i] == pattern[j]) {
            i++;
            j++;
        } else {
            j = nextval[j];
        }
    }

    free(nextval);

    if (j == patternLen)
        return i - j;  // 匹配成功,返回起始位置

    return -1;  // 匹配失败,返回-1
}

int main() {
    char text[] = "ABCABABCDABABCABAB";
    char pattern[] = "ABABCABAB";

    int result = kmpWithNextval(text, pattern);

    if (result == -1)
        printf("Pattern not found in the text\n");
    else
        printf("Pattern found at position: %d\n", result);

    return 0;
}

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

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

相关文章

CANDENCE : 如何绘制元器件

如何绘制元器件 绘制元器件之前先新建一个原理图库。 step1:打开某一个原理图工程 step2:在该工程系下新建一个库文件&#xff0c;如下图&#xff1a; 新建完成&#xff0c;如下图&#xff1a; 右键点击保存&#xff1a;save。 命名并保存&#xff0c;保存的位置自己决定 …

AI - stable-diffusion 艺术化二维码

系列文章&#xff1a; 《AI - stable-diffusion(AI 绘画)的搭建与使用》《AI - AI 绘画的精准控图(ControlNet)》 一、介绍 近日&#xff0c;AI 绘画&#xff08;stable-diffusion&#xff09;用来艺术化二维码算是比较火热的事了&#xff0c;这个 idea 是由国人用 Checkpoi…

Spring Security 实战篇

文章目录 前言内存版(memory)数据库库版(jdbc)自定义登录 - 单体&#xff08;custom-login-single&#xff09;自定义登录 - 前后分离会话一致性方案方案一方案二方案三为什么不用JWT 登录改json方式登录&#xff08;custom-login-json&#xff09;认证密码加密登录&#xff08…

【欧瑞博智能家居】ZigBee Mini网关、超静音智能开合帘电机 添加操作流程

目录 一、添加ZigBee Mini网关 二、添加超静音智能开合帘电机 参考资料 一、添加ZigBee Mini网关 1. 下载《智家365》APP 2. 网关通电&#xff0c;用网线连接路由器的网线接口 3. 再次扫描产品手册里面的二维码添加ZigBee Mini网关&#xff0c;注意手机wifi要在同一个网络…

Nucleo-F411RE (STM32F411)LL库体验 10 - RT-Thread nano finsh的移植

Nucleo-F411RE &#xff08;STM32F411&#xff09;LL库体验 10 - RT-Thread nano finsh的移植 1、Makefile中添加finsh的编译 编译报错如下&#xff1a; 在rtconfig.h添加#include “finsh_config.h” 继续编译&#xff0c;继续报错&#xff1a; 这里是个WEAK函数&#xff…

【python中对点云PCL库的下载安装与配置】

需要的资料&#xff1a; python_pcl-0.3.1-cp36-cp36m-win_amd64.whl 压缩包&#xff1a;pcl-1.12.1-pdb-msvc2019-win64 pcl程序&#xff1a;PCL-1.12.1-AllInOne-msvc2019-win64 网盘链接&#xff1a;https://pan.baidu.com/s/184yY7fc5rqwwd9F4cMncDw 提取码&#xff1a…

SpringSecurity(一):权限管理设计与实现(官文英解+源码调试+基本环境搭建)

权限管理设计与实现 前言权限管理认证授权安全管理框架 整体架构认证AuthenticationManagerAuthenticationSecurityContextHolder 授权AccessDecisionManagerAccessDecisionVoterConfigAttribute 环境搭建技术栈创建项目整合Spring Security 实现原理官方文档解读A Review of F…

Jmeter多接口测试之参数传递

目录 前言&#xff1a; 接口示例 正则表达式提取器 正则表达式提取实例 Json提取器 Json提取器实例 前言&#xff1a; 在进行多接口测试时&#xff0c;有些情况下需要将前一个接口返回数据作为后一个接口的参数&#xff0c;以模拟实际场景。JMeter作为一款常用的性能测试…

【百问百答】可靠性基础知识第六期

1.跌落试验需要确认哪些试验条件? 试验条件包括&#xff1a;释放高度&#xff0c;释放方法和试验表面。 2.什么是跌落试验的试验表面? 试验表面应该是混凝土或者是钢制的平滑坚硬的刚性表面&#xff0c;必要时&#xff0c;可按照相关规范规定其他表面。 3.什么是跌落高度? 指…

云安全技术(二)之云计算参考架构

云计算参考架构 1.1 描述云计算参考架构 Describe Cloud Reference Architecture 多个主要组件组合在一起形成云架构(Cloud Architecture)和云实现的全貌。涉及的组件包括管理和运营云环境的活动(Activity)、角色(Role)和能力(Capability)&#xff0c;以及基于云托管和服务交…

CSDN如何快速获得粉丝和高质量铁粉

✅作者简介&#xff1a;人工智能专业本科在读&#xff0c;喜欢计算机与编程&#xff0c;写博客记录自己的学习历程。 &#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&…

Linux:DNS服务(bind)

目录 环境 主服务器和从服务器的配置环境 主服务器 从服务器 主DNS配置文件 dns从服务器配置 环境 如果你只需要主dns服务器那么你只需要挑着主dns服务器配置看即可 我这里使用了4台虚拟机&#xff0c;你也可以不使用这么多根据你的电脑性能去调整 他们必须要在同一个网段…

什么是渗透测试?渗透等于入侵?

什么是渗透测试&#xff1f; 渗透测试 (penetration test)并没有一个标准的定义&#xff0c;国外一些安全组织达成共识的通用说法是&#xff1a;渗透测试是通过模拟恶意黑客的攻击方法&#xff0c;来评估计算机网络系统安全的一种评估方法。这个过程包括对系统的任何弱点、技术…

6.5 this关键字

1. 关键字&#xff1a;this 1.1 this 是什么&#xff1f; 首先。this在Java中是一个关键字&#xff0c;this 指代的是本类的引用对象 1.2 什么时候使用 this 1.2.1 实例方法或构造器中使用当前对象的成员 1、在实例方法或构造器中&#xff0c;我们在使用get和set方法中使用…

Nucleo-F411RE (STM32F411)LL库体验 9 - RT-Thread nano的移植

Nucleo-F411RE &#xff08;STM32F411&#xff09;LL库体验 9 - RT-Thread nano的移植 1、RT-Thread下载 这一节基于rt-thread nano版本&#xff0c;进行内核的移植&#xff0c;不包含任何组件。移植成功后&#xff0c;可创建任务&#xff0c;串口输出RT-Thread版本信息。 …

【Nginx】Nginx操作命令

Nginx操作命令 1.Nginx原生命令1.1 官方文档1.2 找到命令执行文件1.3 介绍基本操作命令1.3.1 命令帮助1.3.2 启动Nginx1.3.3 Nginx停止、重新加载配置文件&#xff1a;-s signal1.3.4 Nginx查看版本、测试配置文件正确性&#xff1a;-s signal 2.使用系统控制命令 systemctl3.补…

【Unity3D】激光雷达特效

1 由深度纹理重构世界坐标 屏幕深度和法线纹理简介中对深度和法线纹理的来源、使用及推导过程进行了讲解&#xff0c;本文将介绍使用深度纹理重构世界坐标的方法&#xff0c;并使用重构后的世界坐标模拟激光雷达特效。 本文完整资源见→Unity3D激光雷达特效。 1&#xff09;重构…

C++linux高并发服务器项目实践 day12

Clinux高并发服务器项目实践 day12 socket介绍字节序字节序转换函数 socket地址IP地址转换(字符串ip-整数&#xff0c;主机、网络字节序的转换)TCP通信流程套接字函数TCP三次握手TCP滑动窗口TCP四次挥手 socket介绍 socket是网络环境中进程间通信的API&#xff0c;也是可以被命…

CAPL如何仿真ARP报文

文章目录 前言一、环境搭建二、IG生成器仿真ARP报文三、CAPL仿真ARP报文前言 随着智能电动汽车的普及,车载以太网的应用逐渐广泛,所以在汽车电子台架测试过程中,免不了仿真模拟发送以太网报文,本文就介绍两种方法模拟仿真发送以太网ARP报文。 一、环境搭建 CANoe安装 VN5…

FPGA时序约束--实战篇(Vivado添加时序约束)

前面几篇文章已经详细介绍了FPGA时序约束基础知识以及常用的时序约束命令&#xff0c;相信大家已经基本掌握了时序约束的方法。 今天介绍一下&#xff0c;如何在Vivado中添加时序约束&#xff0c;Vivado添加约束的方法有3种&#xff1a;xdc文件、时序约束向导&#xff08;Cons…