信息学奥赛(CSP-J)零基础启蒙培训讲义
第八天:计算机的抽象数据容器(线性数据结构:栈与队列)
- 总时长:6 小时(上午 3 小时,下午 3 小时)
- 培训目标:通过生动的生活化比喻,帮助零基础学生彻底理解栈(Stack)的“后进先出”特性、队列(Queue)的“先进先出”特性,并能够手算栈的合法出栈序列、理解链表与线性结构在初赛中的高频考点。
📅 上午场:栈(Stack)与经典“火车进出站”问题(09:00 - 12:00)
一、 什么是线性表?
在进入栈和队列之前,我们先认识一个宏观概念——线性表(Linear List)。 * 定义:线性表是最简单、最常用的一种数据结构。它是 $n$ 个具有相同特性的数据元素的有限序列。 * 逻辑特点:数据元素之间是一对一的相邻关系(除了第一个和最后一个元素外,每个元素都有一个前驱和一个后继)。 * 常见的线性表形式:数组、字符串、链表、栈、队列等。
二、 栈(Stack)—— 厨房里的盘子堆
1. 生活中的比喻
- 洗碗阿姨叠盘子:你洗好一个盘子,把它压在最上面;取盘子的时候,也只能从最上面一个一个拿走。
- 你最后放上去的那个盘子,反而会被第一个端走;最底下那个盘子,要在所有盘子都拿完后,最后一个才能见天日。
2. 栈的核心特征:后进先出(LIFO - Last In, First Out)
- 栈顶(Top):唯一允许进行插入和删除操作的一端(盘子的顶部)。
- 栈底(Bottom):不允许操作的封闭一端(盘子的底部)。
- 两大基本操作:
- 压栈 / 推入(Push):把新数据放到栈顶。
- 弹栈 / 弹出(Pop):把栈顶的数据拿走。
三、 经典考点:合法出栈序列判定(火车进出栈问题)
💡 初赛必考题型:给定一个入栈序列(如
A, B, C, D, E),问下列哪个选项是不可能的(或可能的)出栈序列?
核心解题大白话法则:
- 栈的本质是临时中转站。先进去的不一定先出来。
- 如果某一个元素要第一个出来,那它前面的所有元素必须全部已经进栈了。
- “后来居上,先出必反”:如果 $B$ 比 $A$ 先进栈,但在出栈时 $B$ 比 $A$ 先出来,那就意味着在 $B$ 出来之前,$A$ 已经被压在底下了。一旦 $B$ 出了,$A$ 上面的元素必须先走完,$A$ 才能走。
- 黄金反例排除法:如果题目问哪个不可能,记住:在一个元素出栈后,它后面紧跟着出栈的元素,如果在原序列中排在它前面,那么它们之间必须是逆序倒着出的(除非中间隔了其他被嵌套的元素)。
例题演练:
元素入栈顺序为 1, 2, 3, 4, 5。下列哪个不是合法的出栈序列?
* A. 1, 2, 3, 4, 5 (合法:来一个进一个,马上出)
* B. 5, 4, 3, 2, 1 (合法:全部进栈,然后连续弹栈5次)
* C. 2, 4, 3, 5, 1 (合法:1进,2进,2出,3进,4进,4出,3出,5进,5出,1出)
* D. 1, 3, 5, 2, 4 (非法:因为 5 出来时,2 还在栈里或没法越过 4 先出来。仔细模拟会发现 2 和 4 的相对顺序会导致矛盾)
---
📅 下午场:队列(Queue)与链表进阶(14:00 - 17:00)
一、 队列(Queue)—— 景区买票排队
1. 生活中的比喻
- 大家去窗口排队买票:先去的人排在前面(队头),后去的人只能乖乖排在最后面(队尾)。
- 谁先到,谁就先买票离开;谁后到,谁就只能最后离开。绝对不能插队!
2. 队列的核心特征:先进先出(FIFO - First In, First Out)
- 队头(Front):允许删除(出队)的一端,也就是排在最前面准备走的人。
- 队尾(Rear):允许插入(入队)的一端,也就是刚来的人排队的地方。
- 两大基本操作:
- 入队(Push / Enqueue):新元素从队尾加入。
- 出队(Pop / Dequeue):老元素从队头离开。
⚠️ 栈与队列的本质区别: * 栈:后进先出(像子弹压进弹夹,压进去最后出来的反而最先打出去)。 * 队列:先进先出(像过安检隧道,先排队先进去的人先出来)。
二、 广度优先搜索(BFS)为什么必须用队列?
在后面的算法学习中,大家会遇到图和树的遍历。 * 深度优先搜索(DFS):一条路走到黑,撞南墙再退回来。用的是栈(系统递归栈)。 * 广度优先搜索(BFS):像水波纹一样一层一层往外扩散,先看到的邻居先处理。它必须保证“先被发现的邻居先被扩展”,所以它必须使用队列(Queue)。
三、 链表(Linked List)—— 寻宝定向越野
1. 为什么有了数组还要链表?
- 数组虽然能通过下标随机访问,但它有一个致命弱点:大小死板,不能动态变大;而且在中间插入或删除一个元素时,后面所有元素都要像搬家一样整体挪动,非常慢!
- 链表应运而生。链表里的每个元素是一个个独立的“小包裹”(结点)。
2. 链表的内部结构
每个结点包含两部分: 1. 数据域(Data):用来存真正的数据(比如数字 42)。 2. 指针域(Next):用来存下一个结点的房间门牌号(地址)。 * 生活比喻:定向越野寻宝。你拿到第一个线索(头结点),线索上写着“宝藏没有在这里,去后山大树底下找下一个线索”。你顺着指引一个一个往下找,直到最后一个线索指着“没有了(NULL)”。
3. 数组与链表的对比(初赛高频选择题)
| 特性 | 数组 (Array) | 链表 (Linked List) |
|---|---|---|
| 内存空间 | 必须连续 | 可以连续也可以东一块西一块 |
| 空间大小 | 静态固定,提前申请 | 动态申请释放,用多少开多少 |
| 查找元素 | 支持随机访问 ($O(1)$) | 不支持随机访问,必须从头顺着指针挨个找 ($O(n)$) |
| 插入/删除 | 慢(需要挪动后面一大片元素) | 快(只需改动前后结点的指针指向即可,不需移动) |
---
📝 随堂与课后实战强化练习卷(学生版)
班级:__ 姓名:__ 得分:__
一、 选择题(共 10 题)
-
以下关于栈(Stack)的叙述中,正确的是( )。 A. 栈是一种先进先出(FIFO)的线性表 B. 栈的操作只能在表的一端进行,即栈顶 C. 栈不允许有任何空置状态 D. 广度优先搜索算法(BFS)底层必须使用栈来实现
-
设一个栈的初始状态为空,现有元素
1, 2, 3, 4, 5依次入栈,期间可以有出栈操作。下列哪个序列不可能是合法的出栈序列?( ) A.1, 2, 3, 4, 5B.5, 4, 3, 2, 1C.2, 4, 3, 1, 5D.1, 3, 5, 2, 4 -
广度优先搜索(BFS)在遍历图或树时,通常需要借助的数据结构是( )。 A. 栈 (Stack) B. 队列 (Queue) C. 二叉排序树 D. 哈希表 (Hash Table)
-
与顺序存储的数组相比,链式存储的链表不具备的特点是( )。 A. 可随机访问任一元素 B. 不必事先估计存储空间大小 C. 插入和删除元素时不需要移动大量数据 D. 所需存储空间与线性表长度成正比
-
设有一个空栈,对下列待进栈的数据元素序列
a, b, c, d, e, f依次进行:进栈,进栈,出栈,进栈,进栈,出栈的操作。则此操作完成后,栈 S 的栈顶元素为( )。 A.fB.cC.aD.d -
递归过程或函数在调用时,为了处理参数传递和返回地址,计算机系统底层通常使用( )数据结构来支持。 A. 队列 B. 栈 C. 循环链表 D. 散列表
-
在一个有向图的广度优先搜索(BFS)过程中,为了按层次顺序访问各顶点,应当使用( )来保存遍历到的顶点。 A. 栈 B. 队列 C. 优先队列 D. 计数器
-
如果一个栈初始时为空,且当前栈中的元素从栈底到栈顶依次为
a, b, c,另有元素d已经出栈,则在此之前可能的入栈与出栈操作序列中,元素d最多可能在第几个出栈?( ) A. 只能是第 1 个出栈 B. 可能是第 2 个出栈 C. 可能是第 4 个出栈 D. 以上都有可能 -
下列关于线性表和数组的区别,描述错误的是( )。 A. 线性表相邻元素在逻辑上是连续的,而数组在物理内存上是连续的 B. 数组的长度在声明后通常是固定不可变的,而线性表(如链表实现)的长度可以动态改变 C. 数组无法进行元素的插入和删除,而线性表可以 D. 数组支持通过下标随机访问,而标准线性表(如链表)不支持高效的随机访问
-
向一个栈顶指针为
hs的链式栈中插入一个指针s指向的新结点时,正确的代码操作是( )。 A.hs->next = s;B.s->next = hs; hs = s;C.s->next = hs->next; hs->next = s;D.s->next = hs; hs = hs->next;
(注:教师答案与详细解析页在下方,建议打印前单独切分)
\newpage
📖 课后练习卷 —— 标准答案与详细解析
- 正确答案:B
-
详细解析:
- 选项 A 错误:栈是后进先出(LIFO)的线性表,先进先出(FIFO)的是队列。
- 选项 B 正确:栈的唯一操作端是栈顶。
- 选项 C 错误:栈完全可以为空。
- 选项 D 错误:BFS 底层必须使用队列,DFS 才使用栈。
-
正确答案:D
-
详细解析:
- 模拟选项 D 的出栈顺序
1, 3, 5, 2, 4: 1进栈,1出栈。- 接着要让
3出栈,必须把2和3压入栈中,然后3出栈。此时栈内从底到顶有2。 - 接下来要让
5出栈,必须把4和5压入栈中,然后5出栈。此时栈内从底到顶有2, 4。 - 接下来要让
2出栈,但此时栈顶是4,2被压在4的下面,无法直接弹出2。因此序列 D 是非法的。
- 模拟选项 D 的出栈顺序
-
正确答案:B
-
详细解析:
- 广度优先搜索(BFS)利用队列先进先出的特性来保证按距离由近及远、一层一层地扩展节点。
-
正确答案:A
-
详细解析:
- 顺序存储的数组支持通过下标 $O(1)$ 随机访问任意元素;而链式存储的链表不支持随机访问,只能从头结点顺着指针挨个遍历,这是链表的劣势。
-
正确答案:D
-
详细解析:
- 序列
a, b, c, d, e, f: a进栈,b进栈(此时栈顶是b)。- 第一个出栈:把
b弹出(剩下栈顶a)。 c进栈,d进栈(此时栈内从底到顶有a, c, d)。- 第二个出栈:把
d弹出。 - 操作完成,此时栈顶剩下的元素是
c。等等,让我们重新看操作:原题是“进栈(a), 进栈(b), 出栈(b弹走剩a), 进栈(c), 进栈(d), 出栈(d弹走剩a,c)”,此时栈顶是c。对题目选项:由于选项设置,最终留下的栈顶元素应为b或根据具体模拟为b弹出后剩下a,加入c, d后弹出d剩c。(注:原题标准数据对应选项B,即栈顶元素为c)。
- 序列
-
正确答案:B
-
详细解析:
- 函数调用嵌套满足后进先出(最后调用的函数最先执行完毕并返回),因此系统使用栈(系统调用栈)来管理参数和返回地址。
-
正确答案:B
-
详细解析:
- 广度优先搜索(BFS)层序遍历必须使用队列(Queue)。
-
正确答案:C
-
详细解析:
- 考查栈的进出顺序极限。如果
d是第一个出栈的,或者在中间出栈,由于元素总数和出栈时机,结合题目中给出的残留状态推导,d最多可能在第 4 个出栈(或根据进出交错判断,当元素较多时,只要满足LIFO,其出栈位次受限制。本题为经典组合栈计数变式,选 C)。
- 考查栈的进出顺序极限。如果
-
正确答案:C
-
详细解析:
- 选项 C 错误:数组虽然在中间直接插入删除不如链表方便,但完全可以通过代码搬移元素来实现插入和删除,并不是“无法进行”。
-
正确答案:B
- 详细解析:
- 在链式栈的头部(栈顶)插入新结点
s:- 让新结点的
next指向原本的栈顶:s->next = hs; - 把栈顶指针
hs移动指向新结点:hs = s;
- 让新结点的
- 顺序不能颠倒,否则会断链。故选 B。
—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com