Skip to content

2.4 串、数组和广义表

计算机程序设计 · 数据结构 · 2.4 串、数组和广义表(零基础讲义)

串、数组和广义表

🎯 一句话秒杀是字符串(找子串、数长度),数组是前面学过的(这里研究矩阵压缩存储),广义表是数组的数组(元素可以是子表)。


① 📊【历年真题考情】

本章(串、数组和广义表)在广东专升本计算机统考中的位置:

项目结论
出题频次⭐⭐⭐⭐(数据结构模块高频稳定考点;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 串的定义

串 = 零个或多个字符组成的有限序列

c
S = "Hello World"    // S是串名,引号内的是串值

术语:

术语定义例子
串长字符个数"Hello" 长度5
空串长度为0的串""
空格串只含空格的串" "(长度3)
子串串中连续片段"ello"是"Hello"的子串
主串包含子串的串"Hello"是主串
位置字符在串中的序号H=1, e=2, ...

3.1.2 串长与 strlen(2024 单选14 / 2026 单选3 必考)

串长 = 字符个数,不含末尾的 '\0'

c
#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. 42026 单选3strlen("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 = 37D. 37 陷阱:忘加空串会选 C(36)

3.1.4 串与线性表的关系(2024 判断8 必考)

串是一种特殊的线性表——数据元素只能是字符

  • 串的逻辑结构和线性表一样(线性结构)
  • 但串的元素只能是字符char),这是它"特殊"的地方
  • 串的基本操作和线性表不同(侧重"找子串""比较""连接",不是"增删改查")

2024 判断8:"串是一种特殊的线性表,其数据元素只能是字符" → 正确

3.1.5 串的存储

c
// 定长顺序存储
typedef struct {
    char ch[MAXLEN];  // 存储字符
    int length;        // 当前长度
} SString;

// 堆分配存储(动态)
typedef struct {
    char *ch;    // 指向动态分配的存储区
    int length;
} HString;

💡 串的存储两种:顺序存储(数组,定长/堆分配)和链式存储(链串)。2024 填空3 就考"串的存储方式"→ 顺序存储、链式存储。

3.1.6 串的模式匹配——找子串位置

BF算法(暴力匹配):

c
// 时间复杂度: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)。

三步法(零基础版):

  1. next[1] = 0(规定)
  2. 对第 j 个字符,看模式串第 1~j-1 个字符组成的子串
  3. 找出这个子串的最长相等前后缀长度 k,则 next[j] = k + 1(若没有相等前后缀,k=0,next[j]=1)

例题:模式串 T = "abaabc" 求 next 数组

j字符前缀子串(1~j-1)最长相等前后缀next[j]
1a(无)0
2b"a"无(长度1无前后缀之分)→ k=01
3a"ab"前缀{a},后缀{b},不等 → k=01
4a"aba"前缀{a,ab},后缀{a,ba} → 相等的是 {a},k=12
5b"abaa"前缀{a,ab,aba},后缀{a,aa,baa} → 相等 {a},k=12
6c"abaab"前缀{a,ab,aba,abaa},后缀{b,ab,aab,baab} → 相等 {ab},k=23

结果:next = [0, 1, 1, 2, 2, 3] 考点拆分说明:KMP 考纲明确列入但近年未直接出计算题,会手算 next 数组即可稳拿

KMP 模式串 abaabc 的 next 数组可视化

3.2 数组(矩阵的压缩存储)

3.2.1 一维/二维数组(回顾)

c
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] 的地址。

逐项推演:

  1. 公式:LOC(i,j) = 1000 + (i×4 + j) × 4
  2. 代入 i=2, j=1:1000 + (2×4 + 1) × 4
  3. = 1000 + (8 + 1) × 4 = 1000 + 9×4 = 1000 + 36 = 1036
  4. 答案: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)存到一维数组的什么位置?

  1. k = 3×(3+1)/2 + 1 = 3×4/2 + 1 = 6 + 1 = 7
  2. 答案: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. 稀疏矩阵

稀疏矩阵: 非零元素个数 << 零元素个数

存储方式:

方法说明特点
三元组(行, 列, 值) 顺序存储节省空间
十字链表每行每列都带头结点的链表适合动态变化
c
// 三元组表示法
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))))

步骤表达式结果
1Tail(L)去掉第一个元素 a,剩 ((b,c), (d,(e,f)))
2Head(Tail(L))取上一步结果的第一个元素 → (b, c)
3Tail(Head(Tail(L)))去掉 (b,c) 的第一个元素 b,剩 (c)
4Head(Tail(Head(Tail(L))))取 (c) 的第一个元素 → c

记忆:Head 往里钻(取元素),Tail 去掉头(剩表)。画括号逐步算,绝不跳步。


④ 🧪【真题同源例题】

例题 1:入门基础题(先热热身)

c
#include <stdio.h>
#include <string.h>
int main() {
    char s[] = "abc";
    printf("%d\n", strlen(s));
    printf("%d\n", sizeof(s));
    return 0;
}

逐项推演:

  1. strlen(s):数可见字符 a、b、c → 3(不含 '\0'
  2. sizeof(s):数组 s 占 4 字节(3 个字符 + 末尾 '\0')→ 4
  3. 输出:
    3
    4

例题 2:2021 真题改编(单选 · 子串数目)

"abcd" 的子串数目(含空串)是(  )

A. 10  B. 11  C. 9  D. 12

逐项推演:

  1. n = 4(4 个字符)
  2. 非空子串数 = 4×5/2 = 10(长度1有4个 + 长度2有3个 + 长度3有2个 + 长度4有1个 = 10)
  3. 含空串:10 + 1 = 11
  4. 答案: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

逐项推演:

  1. 长度:第一层元素 = a(b,c)2
  2. 深度:a 深度1;(b,c) 两层括号 → 深度 2
  3. 答案:A. 2, 2

✅ 对应 2022 单选14(((α,β,γ)) → 1, 2)。套路:长度数第一层逗号分隔的元素,深度数括号嵌套。

例题 4:对称矩阵压缩存储(代入计算)

一个 5×5 对称矩阵(下标从 0 开始),按行优先存下三角(含对角线)到一维数组,求 a[4][2](i=4, j=2,i≥j)的位置 k。

逐项推演:

  1. 公式:k = i(i+1)/2 + j
  2. 代入 i=4, j=2:k = 4×5/2 + 2
  3. = 20/2 + 2 = 10 + 2 = 12
  4. 答案: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]
1a(无)0
2b"a"无 → k=01
3a"ab"前缀{a},后缀{b},不等 → k=01
4b"aba"前缀{a,ab},后缀{a,ba} → 相等 {a},k=12

结果:next = [0, 1, 1, 2] 💡 口诀:next[1]=0;第 j 位看前 j-1 个字符的最长相等前后缀长度 +1


⑤ ⚠️【历年真题高频扣分坑】

#陷阱错误做法正确做法出处
1串长算上 \0strlen("abcd")=5strlen 不含 \0,串长=42024 单选14
2子串数漏空串"software" 子串数算 36公式 n(n+1)/2+1 加空串 = 372021 单选14
3广义表长度数错(a,(b,c),()) 长度算 4长度=第一层=32024 填空4
4广义表深度数错((α,β,γ)) 深度算 3深度=括号嵌套层=22022 单选14
5Tail 忘加括号Tail((a,b,c)) 写成 b,cTail 结果永远是表 (b,c)经典
6对称矩阵公式混淆k 公式用错上/下三角下三角 k=i(i+1)/2+j(i≥j)经典
7稀疏矩阵存储选错动态增删也选三元组三元组顺序存/十字链表动态2024
8子串非连续以为"跳着取"也算子串子串必须连续经典
9next 数组 next[2] 算错next[2] 算成 0next[1]=0 规定;next[2] 看 "a" 无前后缀 → 1考纲考点14
10数组地址忘乘大小LOC=a+9LOC=1000+9×4=10362021/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)))) = ?
👆 点击展开答案
  1. 空串长度为0 ""空格串长度≥1,全是空格
  2. 回溯i = i - j + 2(回到本次匹配开始的下一个位置)
  3. k = i×(i+1)/2 + j(下标从0开始)
  4. 长度=3(3个元素:a, (b,c), (d,(e,f)));深度=3(最多嵌套3层括号)
  5. 先一步步来:
    • 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 — 串、数组和广义表

📺 配套视频

复习到本考点 → 先看视频补讲,再刷上面「闭卷挑战」。

仅供个人学习 · 考生回忆版 · 非考试院原卷