当前位置: 首页 > article >正文

数据结构:串( Bunch)及其实现

什么是串?

串(String)是由零个或多个字符组成的有限序列,比如 "hello" 就是一个串。串是编程中非常常见的数据结构,常用于处理文本数据。

串的特点:

  1. 顺序存储:串中的字符是连续存储的,类似于数组。

  2. 链式存储:串中的字符也可以通过链表的方式存储,每个节点存储一个字符。

  3. 常用操作:包括插入、删除、查找、替换等。


串的存储方式

1. 顺序存储

顺序存储是用数组来存储串中的字符。数组的每个元素存储一个字符,字符之间是连续存储的。

优点

  • 访问速度快,可以通过下标直接访问任意字符。

  • 实现简单。

缺点

  • 插入和删除操作需要移动大量字符,效率低。

  • 数组大小固定,不适合动态变化的串。

C 语言实现

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

#define MAX_SIZE 100  // 串的最大长度

// 定义顺序存储的串
typedef struct {
    char data[MAX_SIZE];  // 存储字符的数组
    int length;           // 串的长度
} SeqString;

// 初始化串
void InitString(SeqString *s, const char *str) {
    strcpy(s->data, str);  // 复制字符串到数组中
    s->length = strlen(str);  // 设置串的长度
}

// 插入字符
int InsertString(SeqString *s, int pos, const char *str) {
    if (pos < 0 || pos > s->length || s->length + strlen(str) > MAX_SIZE) {
        return -1;  // 插入位置不合法或空间不足
    }

    // 将插入位置后的字符往后移动
    for (int i = s->length - 1; i >= pos; i--) {
        s->data[i + strlen(str)] = s->data[i];
    }

    // 插入新字符
    for (int i = 0; i < strlen(str); i++) {
        s->data[pos + i] = str[i];
    }

    s->length += strlen(str);  // 更新串的长度
    return 0;
}

// 删除字符
int DeleteString(SeqString *s, int pos, int len) {
    if (pos < 0 || pos + len > s->length) {
        return -1;  // 删除位置不合法
    }

    // 将删除位置后的字符往前移动
    for (int i = pos + len; i < s->length; i++) {
        s->data[i - len] = s->data[i];
    }

    s->length -= len;  // 更新串的长度
    return 0;
}

// 查找子串
int FindString(SeqString *s, const char *str) {
    for (int i = 0; i <= s->length - strlen(str); i++) {
        int j = 0;
        while (j < strlen(str) && s->data[i + j] == str[j]) {
            j++;
        }
        if (j == strlen(str)) {
            return i;  // 找到子串,返回起始位置
        }
    }
    return -1;  // 未找到子串
}

// 打印串
void PrintString(SeqString *s) {
    printf("串内容:%s\n", s->data);
}

int main() {
    SeqString s;
    InitString(&s, "hello");  // 初始化串
    PrintString(&s);          // 打印串

    InsertString(&s, 5, " world");  // 在位置 5 插入 " world"
    PrintString(&s);                // 打印串

    DeleteString(&s, 5, 6);  // 从位置 5 删除 6 个字符
    PrintString(&s);         // 打印串

    int index = FindString(&s, "llo");  // 查找子串 "llo"
    if (index != -1) {
        printf("找到子串,起始位置:%d\n", index);
    } else {
        printf("未找到子串\n");
    }

    return 0;
}
2. 链式存储

链式存储是用链表来存储串中的字符。每个节点存储一个字符,节点之间通过指针连接。

优点

  • 插入和删除操作效率高,不需要移动大量字符。

  • 适合动态变化的串。

缺点

  • 访问速度慢,需要从头开始遍历。

  • 内存开销大,每个节点需要额外存储指针。

C 语言实现

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

// 定义链式存储的串节点
typedef struct Node {
    char data;           // 存储字符
    struct Node *next;   // 指向下一个节点的指针
} Node;

// 定义链式存储的串
typedef struct {
    Node *head;  // 头指针
    int length;  // 串的长度
} LinkString;

// 初始化串
void InitString(LinkString *s, const char *str) {
    s->head = NULL;
    s->length = 0;

    // 从后往前插入字符,保证顺序正确
    for (int i = strlen(str) - 1; i >= 0; i--) {
        Node *newNode = (Node*)malloc(sizeof(Node));
        newNode->data = str[i];
        newNode->next = s->head;
        s->head = newNode;
        s->length++;
    }
}

// 插入字符
int InsertString(LinkString *s, int pos, const char *str) {
    if (pos < 0 || pos > s->length) {
        return -1;  // 插入位置不合法
    }

    // 找到插入位置的前一个节点
    Node *prev = NULL;
    Node *current = s->head;
    for (int i = 0; i < pos; i++) {
        prev = current;
        current = current->next;
    }

    // 插入新字符
    for (int i = 0; i < strlen(str); i++) {
        Node *newNode = (Node*)malloc(sizeof(Node));
        newNode->data = str[i];
        newNode->next = current;
        if (prev == NULL) {
            s->head = newNode;  // 插入到头部
        } else {
            prev->next = newNode;
        }
        prev = newNode;
        s->length++;
    }

    return 0;
}

// 删除字符
int DeleteString(LinkString *s, int pos, int len) {
    if (pos < 0 || pos + len > s->length) {
        return -1;  // 删除位置不合法
    }

    // 找到删除位置的前一个节点
    Node *prev = NULL;
    Node *current = s->head;
    for (int i = 0; i < pos; i++) {
        prev = current;
        current = current->next;
    }

    // 删除字符
    for (int i = 0; i < len; i++) {
        Node *temp = current;
        current = current->next;
        free(temp);
        s->length--;
    }

    if (prev == NULL) {
        s->head = current;  // 删除的是头节点
    } else {
        prev->next = current;
    }

    return 0;
}

// 查找子串
int FindString(LinkString *s, const char *str) {
    Node *current = s->head;
    int index = 0;

    while (current != NULL) {
        Node *temp = current;
        int i = 0;
        while (temp != NULL && i < strlen(str) {
            if (temp->data != str[i]) {
                break;
            }
            temp = temp->next;
            i++;
        }
        if (i == strlen(str)) {
            return index;  // 找到子串,返回起始位置
        }
        current = current->next;
        index++;
    }

    return -1;  // 未找到子串
}

// 打印串
void PrintString(LinkString *s) {
    Node *current = s->head;
    printf("串内容:");
    while (current != NULL) {
        printf("%c", current->data);
        current = current->next;
    }
    printf("\n");
}

int main() {
    LinkString s;
    InitString(&s, "hello");  // 初始化串
    PrintString(&s);          // 打印串

    InsertString(&s, 5, " world");  // 在位置 5 插入 " world"
    PrintString(&s);                // 打印串

    DeleteString(&s, 5, 6);  // 从位置 5 删除 6 个字符
    PrintString(&s);         // 打印串

    int index = FindString(&s, "llo");  // 查找子串 "llo"
    if (index != -1) {
        printf("找到子串,起始位置:%d\n", index);
    } else {
        printf("未找到子串\n");
    }

    return 0;
}

串的常用算法

1. 模式匹配算法

模式匹配是串的一个重要操作,用于查找子串在主串中的位置。常见的算法有:

  • 朴素算法:逐个字符比较,时间复杂度为 O(n*m)。

  • KMP 算法:通过预处理模式串,减少比较次数,时间复杂度为 O(n+m)。


串的使用场景

  1. 文本编辑器:用于处理文本的插入、删除、查找等操作。

  2. 搜索引擎:用于匹配关键词和网页内容。

  3. 编译器:用于解析源代码中的字符串。


应用实例:文本编辑器

文本编辑器可以用串来实现:

  • 插入文本:在指定位置插入字符串。

  • 删除文本:删除指定位置的字符串。

  • 查找文本:查找指定的关键词。

  • 替换文本:将指定的字符串替换为另一个字符串。


总结

串是一种非常重要的数据结构,常用于处理文本数据。顺序存储和链式存储各有优缺点,适合不同的场景。通过学习串的基本操作和常用算法,你可以更好地解决实际问题。希望通过这篇文章,你能轻松掌握串的相关知识!


http://www.kler.cn/a/555696.html

相关文章:

  • Hadoop-HA集群部署
  • go 模块管理
  • 蓝桥杯 Java B 组之岛屿数量、二叉树路径和(区分DFS与回溯)
  • 【Linux网络编程】IP协议格式,解包步骤
  • List的基本功能(1)
  • 以ChatGPT为例解析大模型背后的技术
  • 数学建模:解锁智能计算的密码!
  • JVM 深入理解与性能优化
  • Qt常用控件之标签QLabel
  • 跨中心模型自适应牙齿分割|文献速递-医学影像人工智能进展
  • QT实战-基于QWidget实现的异形tip窗口
  • 前端vue的一些常见项目启动命令
  • R语言NIMBLE、Stan和INLA贝叶斯平滑及条件空间模型死亡率数据分析:提升疾病风险估计准确性...
  • 鸿蒙5.0实战案例:基于measure实现的文本测量
  • VSCode集成deepseek使用介绍(Visual Studio Code)
  • 2022年下半年试题一:论基于构件的软件开发方法及其应用
  • AI工作流+专业知识库+系统API的全流程任务自动化
  • 网络安全-js安全知识点与XSS常用payloads
  • HTML项目一键打包工具:HTML2EXE 最新版
  • AI学习指南DeepSeek篇(6)-DeepSeek论文介绍