数据结构之串

一、串的定义与基本概念

1. 串的定义

定义:串是由零个或多个字符组成的有限序列,记作 s="a1​a2​...an​",例如 "data structure"、"123" 等。

  • 空串 :无任何字符,长度为 0,用 "" 表示,例如短信内容为空时即为空串。
  • 空格串:由一个或多个空格组成,有长度,例如 " "(3 个空格)。
  • 子串与主串 :子串是主串中连续字符序列。
    • 生活实例:回文诗 "上海自来水来自海上" 是一个串,其正读和反读相同,体现了串的逆序特性;英文单词 "friend" 中,"end" 是子串,"friend" 是主串。

2. 串的比较

规则:基于字符的 ASCII/Unicode 编码逐个比较,直到找到首个不同字符或遍历完较短串。

  • 例 1:"apple" vs "apricot",前两个字符 "ap" 相同,第三个字符 "p"(ASCII 112)<"r"(ASCII 114),故 "apple" < "apricot"。
  • 例 2:"abc" vs "ab",前两个字符相同,短串先遍历完,故 "abc" > "ab"。

二、串的抽象数据类型(ADT)

基本操作

  • 赋值:将一个串的内容复制到另一个串。

  • 比较:逐个字符按ASCII码值比较,决定串的大小关系。

  • 连接:将两个串首尾相连,形成新串。

  • 求子串:从主串的指定位置截取固定长度的子串。

  • 替换:将主串中某子串替换为另一个串。

  • 插入:在指定位置插入子串。

  • 删除:删除主串中指定位置的子串。

生活实例:微信聊天时,发送前编辑文字(赋值)、转发消息(复制)、撤回消息(清空),以及搜索聊天记录中的关键词(定位),都是串操作的典型应用。

三、串的存储结构

1. 顺序存储

  • 用数组存储 ,如 C 语言中用 char str[100] 存储字符串。
  • 优缺点
    • 优点:随机访问快(如取第 5 个字符直接通过下标)。
    • 缺点:插入 / 删除需移动元素,可能溢出。
  • 生活实例:手机短信长度限制(如 70 字),若输入超过,需截断或分段,类似顺序存储的固定容量限制。

2. 链式存储

  • 用链表结点存储字符,每个结点可存多个字符以减少空间浪费。
  • 优点:动态灵活,插入 / 删除方便(如聊天记录不断新增,无需预先分配固定长度)。
  • 缺点:随机访问慢,需遍历。

四、模式匹配算法

1. 朴素模式匹配算法

  • 思路:从主串每个位置开始,逐个字符匹配子串,最坏时间复杂度 O((n−m+1)×m)。
  • 生活实例:在一本小说中查找 "英雄" 一词,每次从当前位置开始逐字对比,若每次都在子串末尾发现不匹配(如主串是 "英雄气短",子串是 "英雄豪杰"),需多次回溯,效率低。

2. KMP 算法

  • 核心思想:利用部分匹配信息避免不必要的回溯。

  • 部分匹配表(Next数组)

    • 定义:next[j] 表示模式串前 𝑗j 个字符的最长公共前后缀长度。

    • 计算示例 (模式串 "ABCDABD"):

      j 0 1 2 3 4 5 6
      模式串 A B C D A B D
      nextj -1 0 0 0 0 1 2
    • 匹配过程:当字符失配时,模式串右移 𝑗−𝑛𝑒𝑥𝑡𝑗j−nextj 位。

  • 时间复杂度:𝑂(𝑛+𝑚)O(n+m),显著优于朴素算法。

六、KMP算法的实现细节

  1. Next数组的推导

    • 初始化 next[0] = -1

    • 通过递推计算每个位置的 next[j],利用已计算的 next 值减少重复比较。

  2. 优化Next数组

    • pattern[j] == pattern[next[j]],则 nextval[j] = nextval[next[j]],进一步减少比较次数。

    • 代码示例:

    #include
    #include
    #include

    // 朴素模式匹配算法
    int naivePatternMatching(const std::string& text, const std::string& pattern) {
    int n = text.length();
    int m = pattern.length();
    for (int i = 0; i <= n - m; ++i) {
    int j;
    for (j = 0; j < m; ++j) {
    if (text[i + j] != pattern[j]) {
    break;
    }
    }
    if (j == m) {
    return i;
    }
    }
    return -1;
    }

    // 计算next数组
    void computeNext(const std::string& pattern, std::vector& next) {
    int m = pattern.length();
    int len = 0;
    next[0] = 0;
    int i = 1;
    while (i < m) {
    if (pattern[i] == pattern[len]) {
    len++;
    next[i] = len;
    i++;
    }
    else {
    if (len != 0) {
    len = next[len - 1];
    }
    else {
    next[i] = 0;
    i++;
    }
    }
    }
    }

    // KMP算法
    int kmpPatternMatching(const std::string& text, const std::string& pattern) {
    int n = text.length();
    int m = pattern.length();
    std::vector next(m);
    computeNext(pattern, next);
    int i = 0;
    int j = 0;
    while (i < n) {
    if (pattern[j] == text[i]) {
    j++;
    i++;
    }
    if (j == m) {
    return i - j;
    }
    else if (i < n && pattern[j] != text[i]) {
    if (j != 0) {
    j = next[j - 1];
    }
    else {
    i = i + 1;
    }
    }
    }
    return -1;
    }

    int main() {
    std::string text = "ABABDABACDABABCABAB";
    std::string pattern = "ABABCABAB";

    复制代码
     // 朴素模式匹配
     int naiveIndex = naivePatternMatching(text, pattern);
     if (naiveIndex != -1) {
         std::cout << "朴素模式匹配: 模式串在主串中的位置是 " << naiveIndex << std::endl;
     }
     else {
         std::cout << "朴素模式匹配: 未找到模式串" << std::endl;
     }
    
     // KMP模式匹配
     int kmpIndex = kmpPatternMatching(text, pattern);
     if (kmpIndex != -1) {
         std::cout << "KMP模式匹配: 模式串在主串中的位置是 " << kmpIndex << std::endl;
     }
     else {
         std::cout << "KMP模式匹配: 未找到模式串" << std::endl;
     }
    
     return 0;

    }

相关推荐
小肝一下40 分钟前
3. 单链表
c语言·数据结构·c++·算法·leetcode·链表·dijkstra
tachibana21 小时前
hot100 前 K 个高频元素(347)
java·数据结构·算法·leetcode
延凡科技14 小时前
多场景落地复盘:端边云架构无人机智能巡检系统设计与实践
大数据·数据结构·人工智能·科技·架构·无人机·能源
皓月斯语20 小时前
B3842 [GESP202306 三级] 春游 题解
数据结构·c++·算法·题解
春日见20 小时前
算法与数据结构----哈希表
数据结构·人工智能·算法·机器学习·自动驾驶·哈希算法·散列表
萌动的小火苗21 小时前
嵌入式开发中的栈与队列:任务调度为什么依赖数据结构
数据结构·c++·单片机·嵌入式硬件
叩码以求索21 小时前
统计按位或能得到最大值的子集数目(一)
数据结构·算法
tachibana221 小时前
hot100 数组中的第K个最大元素(215)
java·数据结构·算法·leetcode
星恒随风21 小时前
C++ STL 栈详解:stack 的使用、经典题目与简单模拟实现
开发语言·数据结构·c++·笔记·学习
txzrxz21 小时前
单调队列讲解
数据结构·c++·算法·单调队列