串、数组和广义表
🎯 一句话秒杀:串是字符串(找子串、数长度),数组是前面学过的(这里研究矩阵压缩存储),广义表是数组的数组(元素可以是子表)。
① 📊【历年真题考情】
本章(串、数组和广义表)在广东专升本计算机统考中的位置:
| 项目 | 结论 |
|---|---|
| 出题频次 | ⭐⭐⭐⭐(数据结构模块高频稳定考点;2026 考纲全解标"⭐⭐⭐、约5分";字符串函数 3/4 年必出) |
| 常考题型 | 单选(2021 单选14、2022 单选14、2024 单选14、2026 单选3)、判断(2024 判断8)、填空(2024 填空3/4) |
| 预估分值 | 8~15 分 / 200 分(约 4%~8%,数据机构模块约35分中占1/4) |
| 考纲归属 | 2026 考纲「数据结构」模块 考点14(串存储、KMP、广义表长度深度) |
考场真实出现过的高频题:
- 2021 单选14:串
"software"的子串数目(含空串)→ 37 - 2022 单选14:广义表
L=((α,β,γ))的长度与深度 → 1, 2 - 2024 单选14:串
"abcd"的长度 → 4(不含'\0') - 2024 填空4:广义表
L=(a,(b,c),())的长度 → 3 - 2024 判断8:串是一种特殊的线性表 → 正确
- 2026 单选3:
strlen("Guangdong")→ 9 - 2026 考纲考点14:KMP 算法 / next 数组(近年未直接出计算题,但考纲明确列入)
🎯 学习目标:学完本章,你能 ① 用公式算出串的子串数目;② 区分 strlen 与 sizeof;③ 一眼看出广义表长度(第一层)和深度(括号层数);④ 手算 KMP 的 next 数组;⑤ 代入数值算数组地址和对称矩阵压缩位置——这五类题就是本章真题的全部考法。
② 🗣️【零基础大白话引入】
串是什么? 串就是字符串——一串排好队的字符。你在聊天框打的每个字、输的每个密码,对计算机来说都是一个"串"。计算机要处理文字,第一步就是学会"数长度、找子串、比较大小"。
数组为什么在这里讲? 数组你已经学过(int a[3][4])。本章研究的是一个"偷懒"技巧:矩阵压缩存储。想象一个 100×100 的对称矩阵(对角线两边一模一样),存全部要 10000 个格子,但既然上下对称,只存一半就够了——这就是"压缩存储",考试考你怎么算压缩后元素的位置。
广义表又是啥? 数组里的元素都是数字;广义表更"自由"——元素可以是另一个表。就像文件夹里可以套文件夹(C = (a, (b, c)),第二个元素是子表)。考试最爱考它的"长度"(第一层有几个元素)和"深度"(套了几层括号),还有 Head/Tail 取元素/取表的递归玩法。
💡 记忆主线:串 = 字符排队(数长度/找子串)→ 数组 = 矩阵压缩(算位置)→ 广义表 = 表里套表(数层数)。本章全是"数数"和"算位置"的送分题,套路固定。
③ 📖【正式核心知识点讲解】
本章知识点 = 考纲要求 + 历年真题实际考过的内容。真题未考、考纲不作要求的超纲内容已剔除或标注"了解"。
3.1 串(String)
3.1.1 串的定义
串 = 零个或多个字符组成的有限序列
S = "Hello World" // S是串名,引号内的是串值术语:
| 术语 | 定义 | 例子 |
|---|---|---|
| 串长 | 字符个数 | "Hello" 长度5 |
| 空串 | 长度为0的串 | "" |
| 空格串 | 只含空格的串 | " "(长度3) |
| 子串 | 串中连续片段 | "ello"是"Hello"的子串 |
| 主串 | 包含子串的串 | "Hello"是主串 |
| 位置 | 字符在串中的序号 | H=1, e=2, ... |
3.1.2 串长与 strlen(2024 单选14 / 2026 单选3 必考)
串长 = 字符个数,不含末尾的
'\0'
#include <stdio.h>
#include <string.h>
int main() {
char s[] = "abcd";
printf("%d\n", strlen(s)); // 4(字符个数,不含 '\0')
printf("%d\n", sizeof(s)); // 5(含末尾 '\0')
return 0;
}✅ 2024 单选14:串
"abcd"的长度 = D. 4 ✅ 2026 单选3:strlen("Guangdong")= 9(9 个可见字符);若问sizeof则 = 10 🚨 一字之差:strlen数"可见字符",sizeof数"占多少字节(含\0)"
3.1.3 子串数目公式(2021 单选14 必考)
长度为 n 的串,子串(含空串)数目 = n(n+1)/2 + 1
公式推导:
- 长度为 1 的子串:n 个(从每个位置开始取 1 个)
- 长度为 2 的子串:n-1 个
- ……长度为 n 的子串:1 个
- 合计非空子串:
n + (n-1) + ... + 1 = n(n+1)/2 - 再加 1 个空串 →
n(n+1)/2 + 1
✅ 2021 单选14:串
"software"(n=8)的子串数目(含空串):8×9/2 + 1 = 36 + 1 = 37→ D. 37 陷阱:忘加空串会选 C(36)
3.1.4 串与线性表的关系(2024 判断8 必考)
串是一种特殊的线性表——数据元素只能是字符
- 串的逻辑结构和线性表一样(线性结构)
- 但串的元素只能是字符(
char),这是它"特殊"的地方 - 串的基本操作和线性表不同(侧重"找子串""比较""连接",不是"增删改查")
✅ 2024 判断8:"串是一种特殊的线性表,其数据元素只能是字符" → 正确
3.1.5 串的存储
// 定长顺序存储
typedef struct {
char ch[MAXLEN]; // 存储字符
int length; // 当前长度
} SString;
// 堆分配存储(动态)
typedef struct {
char *ch; // 指向动态分配的存储区
int length;
} HString;💡 串的存储两种:顺序存储(数组,定长/堆分配)和链式存储(链串)。2024 填空3 就考"串的存储方式"→ 顺序存储、链式存储。
3.1.6 串的模式匹配——找子串位置
BF算法(暴力匹配):
// 时间复杂度:O(n×m)
int Index_BF(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; // 匹配失败
}BF 匹配逐轮推演(主串 S="ababc",模式 T="abc"):
| 轮次 | 比较 | 结果 | 指针动作 |
|---|---|---|---|
| 第1轮 | S[1]=a vs T[1]=a → 相等;S[2]=b vs T[2]=b → 相等;S[3]=a vs T[3]=c → 不等 | 失败 | i 回溯:i = 1-3+2 = 0+2?→ 从主串第2个字符重新开始 |
| 第2轮 | S[2]=b vs T[1]=a → 不等 | 失败 | i 前进到第3个字符 |
| 第3轮 | S[3]=a vs T[1]=a → 相等;S[4]=b vs T[2]=b → 相等;S[5]=c vs T[3]=c → 相等 | 成功 | 返回位置 3 |
💡 BF 的缺点:匹配失败就回溯主串指针,最坏情况 O(n×m)——比如主串全是 a、模式串是 aaa…b 时,每轮都要从头比较。
KMP算法(改进) — 时间复杂度 O(n+m)
核心思想:匹配失败时,主串指针不回溯,只需移动模式串 需要预计算 next数组(部分匹配表)
3.1.7 KMP 的 next 数组计算(2026 考纲考点14 必会)
next 数组怎么手算? 对模式串每个位置 j,看它之前的子串最长"相等前后缀"长度,+1(next[1] 规定为 0)。
三步法(零基础版):
- next[1] = 0(规定)
- 对第 j 个字符,看模式串第 1~j-1 个字符组成的子串
- 找出这个子串的最长相等前后缀长度 k,则 next[j] = k + 1(若没有相等前后缀,k=0,next[j]=1)
例题:模式串 T = "abaabc" 求 next 数组
| j | 字符 | 前缀子串(1~j-1) | 最长相等前后缀 | next[j] |
|---|---|---|---|---|
| 1 | a | (无) | — | 0 |
| 2 | b | "a" | 无(长度1无前后缀之分)→ k=0 | 1 |
| 3 | a | "ab" | 前缀{a},后缀{b},不等 → k=0 | 1 |
| 4 | a | "aba" | 前缀{a,ab},后缀{a,ba} → 相等的是 {a},k=1 | 2 |
| 5 | b | "abaa" | 前缀{a,ab,aba},后缀{a,aa,baa} → 相等 {a},k=1 | 2 |
| 6 | c | "abaab" | 前缀{a,ab,aba,abaa},后缀{b,ab,aab,baab} → 相等 {ab},k=2 | 3 |
结果:next = [0, 1, 1, 2, 2, 3] 考点拆分说明:KMP 考纲明确列入但近年未直接出计算题,会手算 next 数组即可稳拿。

3.2 数组(矩阵的压缩存储)
3.2.1 一维/二维数组(回顾)
int a[3][4]; // 3行4列,共12个元素
// 行优先存储时,a[i][j] 的地址:
// LOC(i,j) = LOC(0,0) + (i×列数 + j) × sizeof(元素)地址计算代入例题:设 int a[3][4],a[0][0] 地址为 1000,每个元素 4 字节,行优先存储,求 a[2][1] 的地址。
逐项推演:
- 公式:
LOC(i,j) = 1000 + (i×4 + j) × 4 - 代入 i=2, j=1:
1000 + (2×4 + 1) × 4 = 1000 + (8 + 1) × 4 = 1000 + 9×4 = 1000 + 36 = 1036- 答案:1036
💡 先数"前面有 i 整行(每行列数个)再数本行前 j 个",共 (i×列数+j) 个元素,再乘元素大小。
3.2.2 特殊矩阵的压缩存储
1. 对称矩阵
特点:a[i][j] = a[j][i]
存储:只需存上三角或下三角(含对角线)a[0][0]
a[1][0] a[1][1]
a[2][0] a[2][1] a[2][2]
...下三角存成一维数组: k = i×(i+1)/2 + j(其中 i≥j)

公式推导(零基础版):
- 要存到
a[i][j](i≥j,下三角),前面有 i 整行 - 第 0 行 1 个元素、第 1 行 2 个元素……第 i-1 行 i 个元素
- 前 i 行共
1+2+...+i = i(i+1)/2个元素 - 本行前面还有 j 个 →
k = i(i+1)/2 + j
代入例题:对称矩阵下三角 a[3][1](i=3, j=1)存到一维数组的什么位置?
k = 3×(3+1)/2 + 1 = 3×4/2 + 1 = 6 + 1 = 7- 答案:k=7(下标从0开始)
2. 三角矩阵
上三角矩阵:下三角全为常数c(存法类似) 下三角矩阵:上三角全为常数c
💡 考试记"常数部分只存一个 c"即可,其余和对称矩阵思路一致。
3. 对角矩阵(三对角矩阵)
非零元素只在三条对角线上:
[ a11 a12 0 0 0 ]
[ a21 a22 a23 0 0 ]
[ 0 a32 a33 a34 0 ]
[ 0 0 a43 a44 a45 ]
[ 0 0 0 a54 a55 ]行优先存储一维数组: 元素总数 = 3n-2
推导:每行最多 3 个非零元,第一行和最后一行各 2 个,中间 n-2 行各 3 个 →
2+3(n-2)+2 = 3n-2
4. 稀疏矩阵
稀疏矩阵: 非零元素个数 << 零元素个数
存储方式:
| 方法 | 说明 | 特点 |
|---|---|---|
| 三元组 | (行, 列, 值) 顺序存储 | 节省空间 |
| 十字链表 | 每行每列都带头结点的链表 | 适合动态变化 |
// 三元组表示法
typedef struct {
int i, j; // 非零元的行下标和列下标
int value; // 非零元的值
} Triple;
typedef struct {
Triple data[MAXSIZE]; // 三元组表
int rows, cols, nums; // 总行数、总列数、非零元个数
} TSMatrix;✅ 2022/2024 常考:稀疏矩阵存非零元素用 三元组表;需要动态增删非零元时用 十字链表。
3.3 广义表
3.3.1 广义表的定义
广义表是线性表的推广——元素可以是单个元素(原子),也可以是另一个广义表(子表)
A = ()
B = (a, b)
C = (a, (b, c)) ← 第二个元素是子表
D = (A, B, C) ← 全部是子表
E = (a, E) ← 递归 = 无限表表示法: 大写字母 = 表名,小写字母 = 原子
3.3.2 广义表长度与深度(2022 单选14 / 2024 填空4 必考)
长度 = 第一层(最外层)元素个数深度 = 括号的最大嵌套层数
逐项推演(2024 填空4): L = (a, (b, c), ())
- 长度:第一层有 3 个元素:
a、(b,c)、()→ 长度 = 3 - 深度:
a深度1,(b,c)深度2,()深度1(空表也算一层括号)→ 深度 = 2
逐项推演(2022 单选14): L = ((α, β, γ))
- 长度:最外层只有一个元素(一个表
(α,β,γ))→ 长度 = 1 - 深度:最外层括号1层 + 里面再1层 → 深度 = 2
- 答案:C. 1, 2
🚨 陷阱:长度数"元素个数"不是"字符个数";
((α,β,γ))长度是 1 不是 3!

3.3.3 表头与表尾(Head/Tail)
| 概念 | 定义 | 例子 |
|---|---|---|
| 表头 | 广义表的第一个元素 | Head((a,b,c)) = a |
| 表尾 | 除表头外的其余元素构成的表 | Tail((a,b,c)) = (b,c) |
| 长度 | 最外层元素个数 | (a,(b,c)) 长度 = 2 |
| 深度 | 括号的最大嵌套层数 | (a,(b,(c))) 深度 = 3 |
🔑 秒杀秘籍
Head 取元素,Tail 取表!
Tail((a,b,c))结果是(b,c)— 始终是一个表(有括号)Head((a,b,c))结果是a— 取出的一个元素(没有括号)考试常考递归取表头表尾:
L = (a, (b, c, d), e)Head(L) = aTail(L) = ((b, c, d), e)Head(Tail(L)) = (b, c, d)
递归取表逐轮推演表(真题风格):
设 L = (a, (b, c), (d, (e, f))),求 Head(Tail(Head(Tail(L))))
| 步骤 | 表达式 | 结果 |
|---|---|---|
| 1 | Tail(L) | 去掉第一个元素 a,剩 ((b,c), (d,(e,f))) |
| 2 | Head(Tail(L)) | 取上一步结果的第一个元素 → (b, c) |
| 3 | Tail(Head(Tail(L))) | 去掉 (b,c) 的第一个元素 b,剩 (c) |
| 4 | Head(Tail(Head(Tail(L)))) | 取 (c) 的第一个元素 → c |
记忆:Head 往里钻(取元素),Tail 去掉头(剩表)。画括号逐步算,绝不跳步。
④ 🧪【真题同源例题】
例题 1:入门基础题(先热热身)
#include <stdio.h>
#include <string.h>
int main() {
char s[] = "abc";
printf("%d\n", strlen(s));
printf("%d\n", sizeof(s));
return 0;
}逐项推演:
strlen(s):数可见字符 a、b、c → 3(不含'\0')sizeof(s):数组 s 占 4 字节(3 个字符 + 末尾'\0')→ 4- 输出:
3 4
例题 2:2021 真题改编(单选 · 子串数目)
串 "abcd" 的子串数目(含空串)是( )
A. 10 B. 11 C. 9 D. 12
逐项推演:
- n = 4(4 个字符)
- 非空子串数 =
4×5/2 = 10(长度1有4个 + 长度2有3个 + 长度3有2个 + 长度4有1个 = 10) - 含空串:
10 + 1 = 11 - 答案:B. 11
✅ 对应 2021 单选14("software" n=8 → 37)。公式
n(n+1)/2+1,别忘加空串。
例题 3:2022 真题改编(单选 · 广义表长度深度)
广义表 L = (a, (b, c)) 的长度与深度分别是( )
A. 2, 2 B. 2, 3 C. 1, 2 D. 1, 3
逐项推演:
- 长度:第一层元素 =
a、(b,c)共 2 个 - 深度:
a深度1;(b,c)两层括号 → 深度 2 - 答案:A. 2, 2
✅ 对应 2022 单选14(
((α,β,γ))→ 1, 2)。套路:长度数第一层逗号分隔的元素,深度数括号嵌套。
例题 4:对称矩阵压缩存储(代入计算)
一个 5×5 对称矩阵(下标从 0 开始),按行优先存下三角(含对角线)到一维数组,求 a[4][2](i=4, j=2,i≥j)的位置 k。
逐项推演:
- 公式:
k = i(i+1)/2 + j - 代入 i=4, j=2:
k = 4×5/2 + 2 = 20/2 + 2 = 10 + 2 = 12- 答案:k = 12
验证:下三角前 4 行共
1+2+3+4=10个元素,第 4 行第 2 列(j=2)前面还有 2 个 → 10+2=12 ✅
例题 5:KMP next 数组手算(考纲考点14)
模式串 T = "abab",求 next 数组。
逐项推演:
| j | 字符 | 前缀子串(1~j-1) | 最长相等前后缀 | next[j] |
|---|---|---|---|---|
| 1 | a | (无) | — | 0 |
| 2 | b | "a" | 无 → k=0 | 1 |
| 3 | a | "ab" | 前缀{a},后缀{b},不等 → k=0 | 1 |
| 4 | b | "aba" | 前缀{a,ab},后缀{a,ba} → 相等 {a},k=1 | 2 |
结果:next = [0, 1, 1, 2] 💡 口诀:next[1]=0;第 j 位看前 j-1 个字符的最长相等前后缀长度 +1
⑤ ⚠️【历年真题高频扣分坑】
| # | 陷阱 | 错误做法 | 正确做法 | 出处 |
|---|---|---|---|---|
| 1 | 串长算上 \0 | strlen("abcd")=5 | strlen 不含 \0,串长=4 | 2024 单选14 |
| 2 | 子串数漏空串 | "software" 子串数算 36 | 公式 n(n+1)/2+1 加空串 = 37 | 2021 单选14 |
| 3 | 广义表长度数错 | (a,(b,c),()) 长度算 4 | 长度=第一层=3 | 2024 填空4 |
| 4 | 广义表深度数错 | ((α,β,γ)) 深度算 3 | 深度=括号嵌套层=2 | 2022 单选14 |
| 5 | Tail 忘加括号 | Tail((a,b,c)) 写成 b,c | Tail 结果永远是表 (b,c) | 经典 |
| 6 | 对称矩阵公式混淆 | k 公式用错上/下三角 | 下三角 k=i(i+1)/2+j(i≥j) | 经典 |
| 7 | 稀疏矩阵存储选错 | 动态增删也选三元组 | 三元组顺序存/十字链表动态 | 2024 |
| 8 | 子串非连续 | 以为"跳着取"也算子串 | 子串必须连续 | 经典 |
| 9 | next 数组 next[2] 算错 | next[2] 算成 0 | next[1]=0 规定;next[2] 看 "a" 无前后缀 → 1 | 考纲考点14 |
| 10 | 数组地址忘乘大小 | LOC=a+9 | LOC=1000+9×4=1036 | 2021/2024 计算 |
📌 最值钱的一条:第 2 条(子串数公式)是 2021 真题单选原题,公式
n(n+1)/2+1必须背——加号后的"1"是空串,最容易漏。
⑥ 📝【课后自测练习题】
1. 串 "data" 的子串数目(含空串)是( )(2021 真题风格)
A. 10 B. 11 C. 12 D. 13
2. 广义表 L = ((a, b), c, (d)) 的长度与深度分别是( )(2022 真题风格)
A. 3, 2 B. 3, 3 C. 2, 3 D. 2, 2
3. 设 int a[3][4],a[0][0] 地址为 2000,元素占 4 字节,行优先存储,则 a[1][2] 的地址是( )(2024 计算风格)
A. 2024 B. 2028 C. 2020 D. 2012
4. 模式串 T = "abac" 的 next 数组是( )(2026 考纲考点14)
A. 0 1 1 1 B. 0 1 1 2 C. 0 1 2 2 D. 0 1 2 1
👆 点击展开参考答案与解析
第1题:B. 11
- n=4,
4×5/2 + 1 = 10 + 1 = 11(别漏空串)
第2题:A. 3, 2
- 长度:第一层
(a,b)、c、(d)共 3 个 - 深度:
(a,b)深2、c深1、(d)深2 → 最大 2
第3题:A. 2024
LOC(1,2) = 2000 + (1×4 + 2) × 4 = 2000 + 6×4 = 2024
第4题:B. 0 1 1 2
- next[1]=0
- next[2]:看"a",无前后缀 → 1
- next[3]:看"ab",前缀{a}后缀{b}不等 → 1
- next[4]:看"aba",前缀{a,ab}后缀{a,ba},相等{a} → 2
📝 原有闭卷真题挑战(保留原内容)
(点击下方空白查看答案)
1. 空串和空格串的区别?
2. 串的 BF 匹配算法中,匹配失败时主串指针怎么移动?
3. 对称矩阵压缩存储时,下三角元素 a[i][j](i≥j) 存到一维数组的哪个位置?
4. 广义表 A = (a, (b, c), (d, (e, f))) 的长度和深度?
5. Head(Tail(Head(Tail(A)))) = ?👆 点击展开答案
- 空串长度为0
"";空格串长度≥1,全是空格 - 回溯:
i = i - j + 2(回到本次匹配开始的下一个位置) k = i×(i+1)/2 + j(下标从0开始)- 长度=3(3个元素:a, (b,c), (d,(e,f)));深度=3(最多嵌套3层括号)
- 先一步步来:
Tail(A) = ((b,c), (d,(e,f)))Head(Tail(A)) = (b,c)Tail(Head(Tail(A))) = (c)Head(Tail(Head(Tail(A)))) = c
📖 教材习题对照
| 教材习题 | 知识点 | 难度 |
|---|---|---|
| 习题4.1~4.2 | 串的基本概念 | ⭐ |
| 习题4.5 | 串的模式匹配 | ⭐⭐⭐ |
| 习题5.1~5.2 | 矩阵压缩存储 | ⭐⭐ |
| 习题5.3~5.4 | 稀疏矩阵三元组 | ⭐⭐⭐ |
| 习题5.5~5.7 | 广义表 | ⭐⭐⭐⭐ |
对应教材:严蔚敏《数据结构》C语言版 第2版 → 第4章 串 + 第5章 数组和广义表 对应考试大纲:考点15 — 串、数组和广义表
📺 配套视频
复习到本考点 → 先看视频补讲,再刷上面「闭卷挑战」。