串的定义与简单的模式匹配
4.1 整节标了 *,教材脚注:「本节不在统考大纲范围,仅供学习参考。」 第 4 章的考纲内容只有一句「字符串模式匹配」。本页把 4.1 的几个定义压缩成一张表,重点放在 4.2.1 的简单模式匹配:它是 KMP 的出发点,KMP 的每一处改进都是针对它的某个缺点。
机制
*4.1 串的定义、基本操作与存储
串(string)是由零个或多个字符组成的有限序列,记为
| 概念 | 定义 |
|---|---|
| 串长 | 串中字符的个数 |
| 空串 | |
| 空格串 | 由一个或多个空格组成的串。空格串不是空串,其长度为空格字符的个数 |
| 子串 / 主串 | 串中任意多个连续的字符组成的子序列称为子串;包含子串的串称为主串 |
| 位置 | 字符在串中的序号;子串的位置以子串第 1 个字符在主串中的位置表示 |
| 串相等 | 长度相等且每个对应位置的字符都相等 |
例:'China Beijing'、'Beijing'、'China',长度分别为 13、7、5;
串与线性表:逻辑结构极为相似,区别仅在于串的数据对象限定为字符集。基本操作差别很大:线性表以单个元素为操作对象,串通常以子串为操作对象。
最小操作子集:StrAssign(赋值)、StrCompare(比较)、StrLength(求串长)、Concat(联接)、SubString(求子串)五种操作不能用其他串操作实现;其他串操作(除 ClearString 和 DestroyString 外)都可以在这个子集上实现。Index(S,T) 是定位操作,不在最小子集中。
| 存储方式 | 要点 |
|---|---|
| 定长顺序存储 | 定长数组 char ch[MAXLEN];超过预定义长度的串值会被舍去,称为截断。串长可以用额外变量 length 存放,也可以在串值后加不计入串长的结束标记 '\0'(隐含值) |
| 堆分配存储 | 仍是一组地址连续的存储单元,但存储空间在程序执行中动态分配(malloc/free) |
| 块链存储 | 类似链式存储;每个结点称为块,可存放一个或多个字符,最后一个结点占不满时通常用 # 补上 |
前两种通常为高级程序设计语言所采用;块链存储仅做简单介绍。
4.2.1 简单的模式匹配算法
模式匹配:在主串中找到与模式串相同的子串,并返回其所在的位置。教材采用定长顺序存储,给出一种不依赖其他串操作的暴力匹配算法:
int Index(SString S, SString T){
int i=1, j=1;
while(i<=S.length && j<=T.length){
if(S.ch[i]==T.ch[j]){ ++i; ++j; } // 继续比较后继字符
else{ i=i-j+2; j=1; } // 指针后退重新开始匹配
}
if(j>T.length) return i-T.length;
else return 0;
}失配时 i=i-j+2:本趟从主串的第
复杂度:设主串和模式串的长度分别为
教材的最坏情况例子:模式串 '0000001',主串的前 45 个字符均为 '0'、第 46 个为 '1'。每趟都比较到模式串的最后一个字符才发现不等,指针
低效的根源:每次回溯后,已匹配的那段主串字符被重新拿来和模式串比较,而这段字符其实就是模式串的某个前缀,可以事先分析。KMP 正是从这一点入手的。
边界
| 说法 | 判断 | 说明 |
|---|---|---|
| 「空格串就是空串」 | ❌ | 空格串的长度为空格字符的个数;空串长度为 0 |
| 「子串可以由不连续的字符组成」 | ❌ | 子串必须是连续的字符 |
| 「串的基本操作和线性表一样以单个元素为对象」 | ❌ | 串通常以子串为操作对象 |
「Index 属于最小操作子集」 | ❌ | 最小子集是赋值、比较、求串长、联接、求子串 |
| 「堆分配存储是链式存储」 | ❌ | 仍是地址连续的存储单元,只是空间动态分配 |
| 「求 | ❌ | 称为模式匹配。求子串是从串中截取第 |
| 「简单模式匹配的时间复杂度是 | ❌ | 理论上是 |
| 「4.1 在统考大纲范围内」 | ❌ | 教材脚注:不在统考大纲范围,仅供学习参考 |
考点
- 空串与空格串;子串的位置用第一个字符的位置表示。
- 简单模式匹配:失配时
i=i-j+2、j=1;最坏。 - 理论复杂度与实际执行时间的区别(4.2.4 第 3 题)。
链接
- 🏠 返回总览:数据结构第 1~4 章总览
- ⬅️ 上一章:3.4 数组和特殊矩阵
- ➡️ 下一节:4.2.2~4.2.3 KMP 算法及其优化
- 📖 名词库:第 1~4 章名词库