字符串与栈

1. 字符串

字符串是数算 B 中较难的内容之一,涉及 KMP 算法、动态规划等。

字符串在内存中主要以顺序表(字符数组)形式存储,也可以用链表存储。字符串以 \0 作为结束标记,对应 ASCII 编码为 0,而不是字符 '0'。

字符型变量与 ASCII

int main(){
    char b, c, d;
    b = 'x';
    c = b;
    d = 120;    // 也对应 ASCII 中的 'x'
}
  • 'A' 的 ASCII 码小于 'a',相差 20。
  • 实际编码可能用 2 个或 4 个字节表示一个字符。

模式匹配

模式匹配的目标是在主串中找到子串(模式串)首次出现的位置,通常返回指针或下标。

朴素模式匹配(回溯)

主串:a b a b c a b c d
模式:a b c

每次匹配失败,模式串向右移动一位,主串指针回退。

时间复杂度:

O(m⋅n) O(m \cdot n)

其中 mm 为模式串长度,nn 为主串长度。

KMP 算法

KMP 算法通过预处理模式串,避免主串指针回退。

核心概念:next 数组,表示模式串每个位置之前的最长相同前后缀长度。

时间复杂度:

O(m+n) O(m + n)
  • O(m)O(m):构造 next 数组。
  • O(n)O(n):匹配过程。

考试中常见题型:根据给定模式串手写 next 数组。

#include <vector>

vector<int> a(10000);  // 预先指定长度可减少内存碎片

2. 栈

定义

栈(Stack)是一种后进先出(Last In First Out, LIFO)的线性表,只允许在一端(栈顶)进行插入和删除。

基本操作:

  • push():入栈
  • pop():出栈
  • top():查看栈顶元素

实现形式

  1. 顺序栈:使用更多,基于数组实现。
  2. 链式栈:栈顶在链表头部,新插入的元素指向旧栈顶。

链式栈出栈时要记得释放节点,否则会造成内存泄漏:

Node* q = top;
top = top->next;
delete q;

栈的应用

  • 进制转换:先得到低位,最后输出,天然适合栈。
  • 括号匹配:左括号入栈,右括号与栈顶匹配。
  • 表达式求值:中缀转后缀、后缀表达式求值。
  • 递归实现:递归调用栈本质上就是系统维护的栈。

关键提醒

要仔细阅读函数声明,理解到底是在修改引用,还是创建了新的局部变量。

有时候,使用功能受限的数据结构(如栈、队列)反而更适合解决算法题。

3. 队列(补充)

队列是先进先出(First In First Out, FIFO)的线性表:

  • 在队尾入队 enqueue()。
  • 在队头出队 dequeue()。

常见应用:

  • BFS(广度优先搜索)
  • 缓冲区 / 任务调度

4. 小结

结构 核心特征 经典应用
字符串 字符序列 模式匹配、文本处理
栈 LIFO 括号匹配、表达式求值、递归
队列 FIFO BFS、缓冲区

KMP 的 next 数组、栈的 LIFO 性质是笔试和上机都常考的重点。