ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

数据结构期末真题提分:判断题到算法设计的过程分攻略

数据结构期末真题提分:判断题到算法设计的过程分攻略

简介:湖北大学数据结构期末试卷(2022—2023学年第一学期A卷)面向计算机与信息工程学院信息安全等专业学生,也可供备考数据结构期末或考研基础复习者自测使用。试卷为闭卷形式,包含判断分析、简答、应用分析等题型,覆盖带权有向图与关键路径、邻接表求边数与入度、顺序查找平均查找长度、出栈序列判定、二叉树先序/中序/后序互推、递归函数fun(x,n)的调用次数、链栈存储结构选择、特殊矩阵与稀疏矩阵压缩、二路归并排序、Prim与Kruskal最小生成树、二叉排序树及ASL、平衡二叉树插入调整和哈希表线性探查等核心考点。资源包仅含1个PDF文件,大小约252KB,排版为7页试题纸,便于打印练习和对照复习。已有376人学习,适合用来梳理章节知识、检验概念理解与算法分析能力,并训练计算题和算法实现题的解题思路。

1. 判断题看着送分,其实是这份卷子最容易丢分的 15 分

某高校计算机类专业的《数据结构》期末卷,四类题型安排得比较稳妥:判断分析 15 分、简答 25 分、应用分析 40 分、程序设计 20 分。多数人复习时把时间全压在最后两道代码题上,真正拉开分差的却是开头那五道判断题——每题 3 分,光写“对/错”只拿 1 分,剩下 2 分全看分析理由写没写到点上。这份 A 卷还偏爱“一定”“只包括”“均为”这类绝对化表述,题干里埋的坑比算法题还密。适合谁来对:正在刷数据结构期末真题、想按题型把分数一档一档抠出来的人,尤其是应用题会做、概念题却总丢分的那批。

2. 判断题与简答题:40 分的概念题怎么答到点上

2.1 五道判断题:先下结论,再补一句“为什么错”

判断题的给分逻辑是“结论 1 分、理由 2 分”,很多人栽在理由写得太虚,比如只写“因为不符合定义”。阅卷时最想看到的是反例或者推导过程,哪怕只有一行。

第一题考关键路径:“使用带权有向图描述工程预计进度,缩短关键路径上某个活动的时间,一定能缩短整个工程工期。”结论是错误。关键路径是当前权值之和最大的那条路径,缩短它上面的活动之后,这条路径的总长变小,一旦它不再是最大,关键路径就转移到了别的路径上,工期由新的关键路径决定,所以“一定能”三个字就是失分点。规范的写法是:结论错误;缩短后若该路径仍为最长路径,工期缩短,若关键路径发生转移,则工期由新的关键路径决定,不一定缩短。

第二题考顺序查找的平均查找长度。这类题最常见的陷阱是把“成功”和“不成功”混着写。等概率下查找成功时 ASL=(n+1)/2;查找不成功时,比较次数取决于实现,不带哨兵的线性表要比较 n 次,带哨兵则是 n+1 次。答题时不要只写一个数字,还要说明前提(等概率、是否带哨兵)。如果卷面写的是“不成功为 (n+1)/2”,那么结论就是错误,理由是 (n+1)/2 是成功情形,不成功情形应为 n(无哨兵)。

第三题考出栈序列:“进栈序列 1,2,3,4,5,6,进栈出栈可穿插,问 2,3,5,1,6,4 是否可能出现。”结论是错误。判断方法只有一条:按给出的输出序列逐个模拟,随时检查栈顶。push 1、push 2、pop 2、push 3、pop 3、push 4、push 5、pop 5,此时栈内从底到顶是 1、4,栈顶是 4,而输出序列的下一位要求是 1,必须先弹 4 才能弹 1,矛盾,所以该序列不可能出现。答题时把每一步的栈状态写出来,比空口说“违反后进先出”得分高得多。

第四题考存储结构的分类:“包括顺序存储、链式存储、哈希存储三种方式。”结论是错误。少了一类:索引存储。数据结构这门课常讲的四类是顺序存储、链式存储、索引存储、散列(哈希)存储。这道题就是靠“少列一项”来卡粗心的人。

第五题考遍历还原:中序 ABCDE、先序 CABED,问后序是否为 BADCE。结论是错误,正确结果应是BADEC。先序首位 C 是根;在中序里 C 左边 AB 是左子树,右边 DE 是右子树;再看先序剩余 ABED,前两个 A、B 属于左子树,后两个 E、D 属于右子树。左子树先序 AB、中序 AB,说明 A 是根、B 是 A 的右孩子;右子树先序 ED、中序 DE,说明 E 是根、D 是 E 的左孩子。后序按“左、右、根”拼起来就是 B、A、D、E、C。

提示:判断题写理由时,能用一句话给出反例就别写三行概念复述,阅卷老师找的是“错在哪”,不是定义。

2.2 邻接表三问:边数、判边、入度,答法完全不同

简答第一题是有向图邻接表的三连问,问得很有层次,答的时候要区分“有向”和“无向”,不然三小问会一起出错。

求边数,看图的类型。无向图的邻接表里每条边被存了两次,所以边数 = 所有顶点邻接表结点个数之和 ÷ 2;有向图每条边只存一次(只存出边),边数 = 所有顶点邻接表结点个数之和。答题时先点明“该图为有向图”,再写统计方式,最后补一句时间复杂度 O(n+e),这一句往往就是拉开细节分的地方。

判断顶点 i 和 j 是否有边,做法是取 i 的邻接表,从头遍历,若链表中出现值为 j 的结点则存在边;无向图因为两边都存,从 i 或 j 任一侧查都可以,有向图只能说明存在 i 到 j 的弧。如果卷面要求更严格,还要补一句“查 i 到 j 只能说明弧<i,j>存在,不能反推出 j 到 i 也有边”。

求顶点 i 的入度是这套题里最容易答错的一问。邻接表只存出边,出度可以 O(1) 数出来,入度不行,必须扫描全部 n 个顶点的邻接表,统计其中值为 i 的结点个数。时间复杂度 O(n+e),因为每条边都要看一次。另一种可行方案是额外建一张逆邻接表,把入度查询降到“数 i 的出边”,代价是多存一份空间。答到“扫描全部邻接表”或者“建立逆邻接表”都算到位,只写“数一数”是不给分的。

2.3 递归函数 fun(x,n):功能、结果、调用次数三问连答

原函数是:n 等于 1 时返回 x,否则返回 x 乘以 fun(x, n-1)。这就是手写的幂运算。

第一问功能:计算 x 的 n 次幂,即 xⁿ,前提是 n 为正整数。

第二问 fun(2,5) 的结果是 32。执行过程中发生的递归调用次数,是这道题真正的考点。fun(2,5) 内部调用 fun(2,4),再调用 fun(2,3)、fun(2,2)、fun(2,1),一共4 次递归调用;如果把最初那次调用也算进去,函数总共被执行 5 次。很多人在这里写 5,丢分就丢在没分清“调用次数”和“函数执行次数”。

第三问 fun(x,n) 最多发生几次递归调用:n-1 次,递归深度为 n。

答这题有个稳妥的模板:先写功能,再写结果,再写“进入函数 n 次、发生递归调用 n-1 次”,把两个数字同时摆出来,阅卷时无论按哪种方式算都能找到对应答案。

2.4 链栈选型、矩阵压缩、顺序表删除改错

链栈那题给了三个候选:带头结点的单链表、不带头结点的循环单链表、带头结点的双链表。答案是带头结点的单链表。理由要写三条:栈只在栈顶一端插入和删除,对应单链表的表头操作,时间复杂度 O(1);带头结点之后,空栈和非空栈的插入删除逻辑统一,不需要对第一个结点单独判空;循环和双向的额外结构对栈没有收益,反而多维护指针。这三条写全,5 分基本就拿稳了。

矩阵压缩那题,问哪种方法失去随机存取功能,答案是稀疏矩阵的三元组表示(十字链表同理)。原因是三元组表只存非零元素的行标、列标、值,且按某种顺序排列,想取第 i 行第 j 列的元素必须从头顺序查找,地址不能由下标直接算出;压缩存储后失去随机存取,本质就是“下标算不出地址”。特殊矩阵(对称矩阵、三角矩阵、带状矩阵)压缩后仍保留地址映射公式,比如对称矩阵按行优先存下三角,可以用公式直接算出 a[i][j] 的存放位置,所以随机存取能力还在。答题时把公式思路写一句,比只写“特殊矩阵不失随机存取”更完整。

顺序表删除第一个元素的改错题,原文有三处问题:形参SqList L是值传递,函数内改length不会传回调用者;没有判断表是否为空;循环移位之后没有把length减 1。改法如下:

/* 删除顺序表第一个元素,成功返回 1,空表返回 0 */ int DelFirst(SqList *L) { int i; if (L->length == 0) return 0; /* 空表必须拦掉,否则下标越界 */ for (i = 1; i < L->length; i++) L->data[i - 1] = L->data[i]; /* 从第二个元素起整体前移一位 */ L->length--; /* 长度不减,等于没删 */ return 1; }

参数从SqList L改成SqList *L(C 语言用指针,C++ 写SqList &L更顺手),这是得分主项;判空和length--是两个附带失分点。改错题的本质是把“参数传递方式”“边界”“状态维护”三件事说清楚,答题时按“错在哪 → 为什么错 → 改成什么”三段写,不会漏。

3. 应用分析题:五道计算题的推演过程一次写全

3.1 二路归并排序:每趟结果必须一行一行排

题目序列是 {15,5,16,2,25,8,20,9,18,12},要求写升序每趟结果。归并排序的“一趟”指把长度为 L 的有序段两两合并成长度 2L 的有序段,从 L=1 开始,所以第一趟是把相邻两个元素各自排好,不是整体排一次。

第一趟:{15,5}→5,15;{16,2}→2,16;{25,8}→8,25;{20,9}→9,20;{18,12}→12,18,结果为 5,15,2,16,8,25,9,20,12,18。

第二趟:{5,15} 与 {2,16} 合并为 2,5,15,16;{8,25} 与 {9,20} 合并为 8,9,20,25;{12,18} 单独成段,结果为 2,5,15,16,8,9,20,25,12,18。

第三趟:{2,5,15,16} 与 {8,9,20,25} 合并为 2,5,8,9,15,16,20,25;{12,18} 照抄,结果为 2,5,8,9,15,16,20,25,12,18。

第四趟:{2,5,8,9,15,16,20,25} 与 {12,18} 合并为 2,5,8,9,12,15,16,18,20,25,有序段长度达到 16,大于元素个数 10,排序结束。

写这题最容易犯的错是“段长翻倍”写错,或者合并时把剩余段丢了。稳妥做法是每趟标一下有序段长度 1→2→4→8→16,只要长度序列对,中间结果基本不会错。另外每趟都要写完整序列,只写“合并后得到……”不写全,容易丢过程分。

3.2 Prim 与 Kruskal:把候选边表填成“过程证据”

最小生成树这题卷面配了带权无向图,以顶点 0 为起点。图的具体边权以卷面为准,能背的是书写格式,因为这类题 8 分里,过程分通常占 5 分以上。

Prim 的答题格式建议做成一张逐步表:列“已选顶点集 U”“候选边(含权)”“本步选中的边”。每一步只做三件事:把新加入顶点的所有邻边放进候选池,去掉会成环的边(一端已在 U 内的边),从池里取权值最小的那条,把对端顶点并入 U。重复到 U 含全部顶点。写的时候每一步都要显示“候选池里当时有哪些边”,只写“选权最小的边”等于没写过程。

Kruskal 完全不同,它不看起点,先按边权从小到大排序,依次取边,用并查集判断两端点是否已在同一连通分量,不在就选入并合并,在就丢弃,选满 n-1 条边立即停止。答题时把边按权排序列一行,再逐条标“选/弃 + 理由(是否成环)”,最后画或写出选中的 n-1 条边。

两者放同一题里,最容易混的是“Prim 从顶点出发、Kruskal 从边出发”。有个记忆点:Prim 的候选池永远是“已选集合与未选集合之间的边”,所以每步只更新一小圈;Kruskal 的视角全局铺开,靠判环控制。

注意:如果卷面图里有几条边权相同,Prim 和 Kruskal 都可能有多种合法结果,只要总权值相同、边数 n-1、无环,都算对,但过程必须自洽。

3.3 二叉排序树:还原、中序、两个 ASL

题目给先序 (12,5,2,8,6,10,16,15,18,20),要求构造二叉排序树并求平均查找长度。

构造按“先序第一个是根、后面比根小的归左子树、比根大的归右子树”递归划分。12 是根;5,2,8,6,10 都小于 12,进左子树;16,15,18,20 进右子树。左子树先序第一个 5 为根,2 小于 5 做左孩子,8,6,10 大于 5 进右子树,8 为根,6 左、10 右。右子树 16 为根,15 左,18,20 大于 16,18 为根,20 做 18 的右孩子。

中序遍历的结果就是 2,5,6,8,10,12,15,16,18,20,升序,这本身就是二叉排序树的性质,可以用来自检:中序不是升序,树一定画错了。

查找成功的 ASL 按“每个结点的比较次数 = 所在层数”算。层数分布:12 在第 1 层;5、16 在第 2 层;2、8、15、18 在第 3 层;6、10、20 在第 4 层。总和 1+2×2+3×4+4×3=29,ASL成功 = 29/10 = 2.9。

查找不成功要补外部结点(空指针),n 个结点共 n+1=11 个失败结点。失败结点的比较次数取其双亲所在层数:2 的两个空指针取 3,6、10、20 的空指针各两个取 4,15 的两个空指针取 3,18 的左空指针取 3。合计 2×3+2×4+2×4+2×3+1×3+2×4 = 39,ASL不成功 = 39/11 ≈ 3.55。

这两个数字是这类题的固定收尾,写的时候把“分子怎么来、分母是谁”各写一句,比只丢两个结果更稳。

3.4 平衡二叉树:四次插入里藏了三种旋转

序列 {4,5,7,2,1,3,6},逐步插入并写出调整过程。

插 4:树为单个结点 4。插 5:5 大于 4,做右孩子,平衡因子 -1,无需调整。插 7:4-5-7 形成右右链,最小不平衡子树的根是 4,属RR 型,对 4 左旋,5 上升为根,4 为其左孩子,7 为右孩子。

插 2:2 小于 5 进左子树,小于 4 做 4 的左孩子;此时 4 的平衡因子 +1、5 的为 +1,均未超限。插 1:1 落在 2 的左边,4 的左子树高 2、右子树高 0,平衡因子 +2,最小不平衡子树根为 4,属LL 型,对 4 右旋,2 上升,2 的左孩子是 1、右孩子是 4,整树根仍为 5。

插 3:3 先小于 5 进左,大于 2 进右,小于 4 做 4 的左孩子。此时 5 的左子树高 3、右子树高 1,平衡因子 +2,且较高子树(左孩子 2)的右子树更高,属LR 型。调整分两步:先对 2 左旋,让 4 顶上来,2 变成 4 的左孩子、3 变成 2 的右孩子;再对 5 右旋,4 成为整树根,左孩子 2(带 1 和 3),右孩子 5(右孩子 7)。

插 6:6 大于 4 进右,大于 5 进右,小于 7 做 7 的左孩子。此时 5 的左子树为空、右子树高 2,平衡因子 -2,较高子树(右孩子 7)的左子树更高,属RL 型。先对 7 右旋,6 顶上来、7 变成 6 的右孩子;再对 5 左旋,6 成为 4 的右孩子,6 的左孩子是 5、右孩子是 7。最终树为:根 4,左子树 2(左 1、右 3),右子树 6(左 5、右 7),完全平衡。

这题的关键不是画树,是判断旋转类型。判断依据是“最小不平衡子树的根,其较高子树往哪边偏”:偏高子树在左、左子树的左子树更高是 LL,左子树的右子树更高是 LR,右边对称。很多人按“插入位置”判类型,插入点在第几层就往哪边算,结果 LR 和 RL 全反。

3.5 哈希表线性探查:装表容易,失败 ASL 才见功底

关键字 {32,13,49,24,38,21,4,12},H(key)=key%7,线性探查,地址空间 0~9。

逐个装表:32%7=4,放 4;13%7=6,放 6;49%7=0,放 0;24%7=3,放 3;38%7=3 冲突,顺延到 5;21%7=0 冲突,顺延到 1;4%7=4 冲突,5、6 已占,落到 7;12%7=5 冲突,6、7 已占,落到 8。最终表为:0:49,1:21,2:空,3:24,4:32,5:38,6:13,7:4,8:12,9:空。

查找成功 ASL 按每个元素的探查次数算:32、13、49、24 各 1 次;38 从 3 探到 5 共 2 次,21 从 0 探到 1 共 2 次;4 从 4 探到 7 共 4 次;12 从 5 探到 8 共 4 次。总和 16,ASL成功 = 16/8 = 2。

查找失败 ASL 是这题的分水岭。做法是对散列函数每一个可能取值(0~6,共 7 个)分别计算“从该地址开始探查,直到遇到空单元为止的比较次数”,再取平均:H=0 走 0→1→2,3 次;H=1 走 1→2,2 次;H=2 直接命中空位,1 次;H=3 走 3 到 9 才遇空,7 次;H=4 走 4 到 9,6 次;H=5 走 5 到 9,5 次;H=6 走 6 到 9,4 次。合计 28,ASL失败 = 28/7 = 4。

分母取 7 而不是 8 或 10,是因为失败查找的起点只能是散列函数能算出的地址,这一点写错,整题白算。

4. 程序设计题:两道算法大题的递归模型与可提交代码

4.1 求二叉树中度为 2 的结点个数

题目给了二叉链表结点类型,要求先设计递归模型再写函数。这道题的递归模型要写两行:终止条件 f(空树)=0;递推式分两种情形——当前结点有两个孩子时 f(b)=1+f(b->lchild)+f(b->rchild),否则 f(b)=f(b->lchild)+f(b->rchild)。

/* 统计二叉树 b 中度为 2(左右孩子都存在)的结点个数 */ int CountTwo(BTNode *b) { if (b == NULL) /* 空树没有度为 2 的结点 */ return 0; if (b->lchild != NULL && b->rchild != NULL) return 1 + CountTwo(b->lchild) + CountTwo(b->rchild); /* 本结点计数,再递归左右 */ else return CountTwo(b->lchild) + CountTwo(b->rchild); /* 本结点不计数,只递归 */ }

代码只有一处需要解释:为什么不能写成return (b->lchild!=NULL && b->rchild!=NULL) + CountTwo(...) + CountTwo(...)。能写,但阅卷时不如显式分支好读,而且题目要求“给出递归模型的设计”,分支写法与模型一一对应,讲得清。时间复杂度 O(n),每个结点访问一次;空间复杂度 O(h),h 为树高,递归栈深度。

写这类题有一个固定检查顺序:先写终止条件(漏了必崩),再写“本层要做什么”,最后写“交给左右子树”。中间那步是本题唯一的 1 分,写丢就变成“求结点总数”了。

4.2 删除单链表中值最小的所有结点

题目是带头结点的单链表,删除最小值结点,且最小值可能有多个。稳妥解法是两趟:第一趟求最小值,第二趟边扫边删。

/* 删除带头结点单链表 L 中所有值为最小值的结点 */ void DelNode(LinkList *L) { LNode *p, *pre, *q; ElemType min; if (L == NULL || *L == NULL) return; /* 头指针或头结点为空,直接返回 */ p = (*L)->next; if (p == NULL) return; /* 空表没有数据结点 */ min = p->data; for (; p != NULL; p = p->next) /* 第一趟:扫描出最小值 */ if (p->data < min) min = p->data; pre = *L; /* pre 始终指向 p 的前驱 */ p = (*L)->next; while (p != NULL) { if (p->data == min) { /* 命中最小值,摘下并释放 */ q = p; pre->next = p->next; p = p->next; free(q); } else { /* 不是最小值,pre 才后移 */ pre = p; p = p->next; } } }

三个参数各管一件事:pre是删除必需的前驱指针;p是工作指针;q暂存待释放结点。最容易写错的是pre的移动位置——只有没删结点时才后移,删了结点 pre 不能动,否则会跳过结点或者断链。带头结点这个条件帮了大忙:第一个数据结点也有前驱,不用单独处理“删除头结点”的特例。

函数声明是DelNode(LinkList *L),说明调用方传的是头指针的地址,函数内用*L取头结点,这是“要修改链表本身”的标准写法,写成LinkList L值传递,删除操作对调用方完全不可见。

4.3 从这两题抽象出的四步框架

这两道题一个在树上、一个在链表上,但答题框架一模一样:第一步写清数据结构定义与参数含义;第二步写终止/边界条件(空树、空表、单结点);第三步写本层核心动作(计数、删除);第四步说明时间与空间复杂度。四步写全,即使代码有小笔误,过程分也能拿大半。

考场上代码题不要求编译通过,阅卷看的是“边界有没有考虑、指针有没有维护、复杂度说得对不对”。指针题尤其如此:凡涉及删除,必须先想前驱从哪来;凡涉及递归,必须先想终止条件写在哪。这两句话几乎能套住全部链表与二叉树大题。

5. 易错点:五个反复丢分的地方

5.1 平均查找长度把“成功”和“不成功”混着算

错在哪:顺序查找写成“ASL=(n+1)/2”就收笔,不区分成功与失败;哈希表算失败 ASL 时,分母随手写成元素个数或表长。

为什么错:成功 ASL 统计的是“查每个已存元素需要比较几次”,失败 ASL 统计的是“从每个可能的散列地址出发,探到空位需要几次”。两者的分子分母来源都不同,混用必错。

怎么答对:顺序查找先声明前提(等概率、是否带哨兵),成功给 (n+1)/2,不成功给 n 或 n+1。哈希失败 ASL 的分母是散列函数的取值个数(模 7 就是 7),分子是各起点探查长度之和,一步一步写出来。

5.2 看到“缩短关键路径”就默认工期会变短

错在哪:判断题里直接判“正确”,理由写“关键路径决定工期”。

为什么错:关键路径是动态的。缩短之后原关键路径可能不再是最大的那条,关键路径转移,工期由新路径决定,缩短效果被抵消甚至为 0。

怎么答对:答“不一定”,补一句“只有当缩短后该路径仍为最长路径时,工期才缩短;否则关键路径转移”。这一句就是 2 分理由分。

5.3 出栈序列靠“感觉”判断,不模拟栈

错在哪:盯着序列看几眼,觉得“大概符合后进先出”就判对。

为什么错:进出栈可以任意穿插,人眼很难同时跟踪栈内状态,序列越长越容易看错。

怎么答对:永远手写模拟。按输出序列逐位推进,需要谁出栈就先把谁之前没进栈的元素依次压入,然后检查栈顶是不是要出的那个。本题模拟到第 4 位就出现“栈顶是 4、却要出 1”的矛盾,结论立刻出来。

5.4 平衡二叉树的旋转类型按插入位置判断

错在哪:看到新结点插在左子树的右边,就直接写 LR,不检查最小不平衡子树的根在哪。

为什么错:旋转类型由“最小不平衡子树的较高子树方向 + 该较高子树的较高子树方向”决定,和插入点在整棵树里的绝对位置无关。最小不平衡子树的根可能是中间某一层,不是整棵树的根。

怎么答对:每次插入后从插入点向上找第一个平衡因子绝对值超过 1 的结点,以它为根判断两层的偏移方向。本题插入 3 时,最小不平衡子树的根是 5 而不是 4,判成 LR 才对;判成 LL 就会把树转歪。

5.5 改错题只改语句,不改参数传递方式

错在哪:把for循环里的下标改来改去,或者补一句L.length--,却没发现形参是值传递。

为什么错:C 语言里void del(SqList L)拿到的是一份副本,函数里怎么改都不影响调用者的表。下标和长度改得再对,调用方看到的顺序表纹丝不动。

怎么答对:先看形参,值传递的一律改成指针(C++ 可写引用),再补判空和长度维护。答题顺序固定为“参数 → 边界 → 状态”,三样都点到才算完整。

6. 上考场前:时间分配、检查顺序与押题方向

这门课的卷面节奏很好把握:判断 15 分、简答 25 分、应用 40 分、程序 20 分。建议的时间切法是判断 15 分钟、简答 30 分钟、应用 60 分钟、程序 30 分钟,留 15 分钟回头补过程。应用题是分数比较集中的部分,五道题每题 8 分,宁可少写一道代码题,也别让某道应用题只写个答案没有过程。

检查顺序也有讲究,按“性价比”从高到低排:

检查项典型失分补救动作
判断题理由只写对错,理由空泛每题补一句反例或推导
归并/排序每趟漏写某一趟或段长写错补标段长 1→2→4→8
哈希失败 ASL分母写成元素个数改成散列函数取值个数
树形题画图只写序列不画结构补画树形,标层号
代码题边界空树空表没判头两行补终止条件

押题方向按这份卷子的偏好推:图论必考最小生成树与关键路径的概念辨析;树必考遍历还原 + 二叉排序树 ASL 或平衡树调整;查找必考哈希线性探查的两个 ASL;排序必考归并或快排的每趟结果;代码题大概率还是“二叉树递归统计”和“单链表删除”这两个套路,因为它们的递归模型和指针维护最能考出基本功。

我自己的习惯是:每次拿到卷子先把五道应用题的题干扫一遍,把最有把握的那道先做完,用它的过程格式给整张卷子定调——表格、步骤编号、结论分行。以前吃过一次亏,第一道应用题写得潦草,后面几道明明会做,也跟着写得乱七八糟,最后过程分丢了一半。从那以后我每道计算题都强制走一遍“列初始状态、写每步操作、标最终结果”三步,再赶时间也不省。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进