
2025年3月的GESP C七级考试结束两个多星期了这几天陆续有学生拿着回忆版的选择题和判断题来找我对答案。我自己也把这套客观题按考点重新梳了一遍发现不少题出得很有迷惑性——尤其那些看起来在考语法、实际在考数据结构和算法边界的题。趁着题目还在脑子里热乎我把它整理成一份完整的题解选择题15道、判断题10道逐题拆解法思路和易错点同时把考场上的做题节奏建议也一起写了。需要说明的是本文不搬运试卷原文所有题目均根据多位考生回忆还原为近似表述但核心考点和解题逻辑是准确的。这篇题解适合三类人一是已经考过七级、想核对结果的考生二是准备下半年考七级、想摸清出题风格的备考生三是教C的同行可以参考我的讲法把难点给学生拆开讲。1. 2025年3月七级试卷的命题特征客观题到底在考什么1.1 题型构成与考察范围速览先看整体结构。按照考生反馈这场考试的客观题部分是15道单选题加10道判断题合计50分和考试大纲的分值比例一致。选择题绝大多数是四选一判断题则对给定陈述做真假判断。从考察范围看七级的知识点分配大致如下表知识点板块选择题题量判断题题量主要出题方向C类和对象、深浅拷贝32构造函数、析构时机、拷贝语义指针与动态内存11new/delete、悬空指针树与堆21二叉树性质、堆调整过程图论基础与遍历32邻接表/邻接矩阵、DFS/BFS、最短路径排序与复杂度11稳定性、Big-O量级递归、动态规划、贪心32状态转移、递归栈、贪心正确性STL用法11vector扩容、容器底层结构位运算与数学基础10位运算优先级、简单数论这个比例基本是七级考试的常态数据结构与算法占了大头语法层面只剩两成左右剩下的是复杂度和数学基础。和六级最大的差异在于六级还大量考这段代码输出什么七级则更多考这个算法为什么对、复杂度是多少。1.2 难度变化阅读理解题增多判断题文字陷阱更深对比前两年的同级别试卷我印象最深的一点是今年把代码阅读理解类的选择题增加了。所谓阅读理解就是给一段不超过15行的C代码问程序输出结果或某个变量的变化过程。这类题要求考生具备扎实的手推代码能力因为代码里往往嵌了二重循环加条件分支粗心一步就会推错边界。另一个变化是判断题的文字陷阱更隐蔽。比如有一道关于堆的判断题表述是在小根堆中从任意节点出发向上找到的路径上的节点值一定单调递减。这句话是对的——因为堆的性质就是父节点小于等于子节点向上走父节点只会更小路径值必然单调递减。但不少考生在考场上纠结堆排序而不是堆本身的性质把自己绕进去了。这种题考的就是定义是否吃透。2. 选择题逐题解法复盘从语法细节到算法综合2.1 类和对象、深浅拷贝最容易到手也最容易马虎的分数选择题前几道通常是语法题这次把语法细节放进了真实场景里考。印象最深的是一道关于拷贝构造的题回忆整理后的表述定义了一个类内部有一个int* p;成员。如果直接使用编译器默认生成的拷贝构造函数将对象a拷贝给b随后a和b都离开作用域时程序运行最可能出现什么问题四个选项分别是正常结束、重复释放导致未定义行为、编译报错、b的数据丢失。答案是重复释放导致未定义行为这是标准的浅拷贝问题。为什么编译器默认的拷贝构造函数做的是逐成员拷贝memberwise copy不会为指针成员重新分配内存。拷贝完成后a.p和b.p指向同一个堆地址。当a离开作用域时析构函数释放掉该地址随后b离开作用域析构函数再一次释放同一个地址。同一块内存被delete两次C标准将其定义为未定义行为最常见的结果是程序崩溃但也可能碰巧没事——这恰恰是最危险的因为这种bug在开发阶段很难稳定复现。我给学生讲浅拷贝时常用一个比喻两个人都拿同一把门锁的钥匙第一个人走了把锁换了第二个人还用旧钥匙开门自然就出事。深拷贝则是给第二个对象重新配一把锁和新钥匙互不影响。这道题正确率其实不低但依然有人选编译报错估计是把没写构造函数、编译器自动生成一个和拷贝构造函数的自动生成记混了。编译器生成的默认拷贝构造函数是合法的只是语义上存在隐患。2.2 图论基础与遍历七级的重头戏图论的题这次出得比较集中选择题里至少三道和图的存储、遍历相关。其中一道DFS复杂度的题值得展开讲已知一个无向图采用邻接表存储顶点数为n、边数为m。从某个顶点出发做深度优先遍历访问所有可到达顶点的时间复杂度是多少A. O(n) B. O(m) C. O(nm) D. O(n×m)答案是C。最容易错选的是B很多人直觉认为遍历只跟边有关忽略了在邻接表结构里找邻接点需要逐个扫描每个顶点的边链表。每个顶点最多被访问一次每次访问时又要检查它对应的边链表由于无向图的每条边同时出现在两个顶点的链表中所有边最多被扫描两次所以总复杂度是O(nm)。同理用邻接表实现BFS也是O(nm)。另一道关于Dijkstra的题回忆出来是这样用Dijkstra算法求单源最短路径每轮从未确定最短距离的顶点中选择一个距离最小的顶点。如果使用优先队列二叉堆实现这一操作每次选择的时间复杂度是多少答案是O(log n)。题目本身不难但它把算法原理和数据结构选型绑在一起考——如果不知道优先队列为什么能把Dijkstra从O(n²)优化到O((nm)log n)这道题就无从下手。说到图顺手把邻接矩阵和邻接表的复杂度对照写在这里七级考生必须烂熟于心操作邻接矩阵邻接表判断两点是否相邻O(1)O(度)遍历某个顶点的所有邻接点O(n)O(度)存储空间O(n²)O(nm)适合场景稠密图稀疏图这张表选择题会直接考判断题也会绕着它出。2.3 动态规划与递归区分算法思想的经典考法今年有一道选择题特别有代表性考的是最长上升子序列LIS的动态规划解法。题目大意是给定数组a长度为n定义dp[i]表示以a[i]结尾的最长上升子序列长度。以下哪个转移方程是正确的A. dp[i] max(dp[j] 1)其中j i且a[j] a[i] B. dp[i] dp[i - 1] 1 C. dp[i] max(dp[i - 1], dp[j] 1)其中j i且a[j] a[i] D. dp[i] dp[i - 1] (a[i] a[i - 1] ? 1 : 0)答案是A。C选项极具迷惑性。关键在于dp[i]的定义以a[i]作为最后一个元素的最长上升子序列长度——注意这并不要求a[i]是全局最长子序列的末尾所以dp数组本身不是单调递增的。转移时必须枚举所有j i且a[j] a[i]用dp[j] 1去更新dp[i]最终再从整个dp数组里取最大值。C选项里的max(dp[i - 1], ...)暗含了dp[i - 1]可以代表前缀最优的假设在LIS的定义下并不成立。对应代码如下vectorint dp(n, 1); for (int i 1; i n; i) { for (int j 0; j i; j) { if (a[j] a[i]) { dp[i] max(dp[i], dp[j] 1); } } } int ans 0; for (int i 0; i n; i) { ans max(ans, dp[i]); }这类DP选择题几乎从不直接问什么是动态规划而是给具体问题的状态设计和转移方程让你判断对错。所以平时学DP不能只背代码要把状态数组的含义和转移逻辑用自然语言复述一遍做到看到题就能识别转移方程语义是否自洽。2.4 STL与位运算基础分也不能丢七级题库里STL通常占1到2分。这次考了vector扩容当vector的size等于capacity时继续push_back会发生什么答案是重新分配一块更大的内存把原元素搬移过去然后释放旧内存。这里有个多数考生容易忽略的细节vector扩容不一定按翻倍策略实现C标准只要求插入操作满足均摊O(1)复杂度具体扩容因子由编译器实现决定。有的教材直接写每次扩容为原来的2倍严格来说不算错但不能把它当成C标准内容。假如判断题里出现每次扩容为原来的2倍并让你判断对错它是假的——标准没有这个要求。这次没考这一点但备考时一定要把这个边界搞清楚。位运算考了一道很基础的题1 4的结果以及位运算优先级和加减法的关系。前者答案是16后者就有点讲究了C中加法的优先级高于移位运算符。比如1 2 1实际会先算2 1结果是8而不是4。这类容易在代码里翻车的细节正是出题人偏爱的地方。3. 判断题陷阱地图哪些表述最容易误判3.1 被一定必须总是坑到的一批判断判断题总体难度在七级里不算高但每年都能筛掉一批基本功不扎实的考生。陷阱大多藏在副词和边界条件里我挑几道有代表性的展开讲。其中一道是在C中对同一个无序数组执行sort排序使用快速排序的实现一定是不稳定的。这道题是错的。C标准里的std::sort只保证平均时间复杂度为O(n log n)并不保证具体是哪种排序算法。至于稳定性标准明确规定std::sort不保证稳定很多实现确实使用不稳定快排或内省排序。但不能保证稳定不等于一定不稳定一个实现完全可以在快排基础上保持稳定性只要满足复杂度要求。这里考的是不确定性和否定性的逻辑差别很多同学把不保证稳定直接等价成一定不稳定就被绕进去了。补充一点C标准里真正保证稳定的是std::stable_sort通常用归并排序的变体实现代价是可能需要额外内存。另一道使用二分查找算法时只要数组是有序的就一定能正确查找到目标值。这道题错。有序只是必要条件而非充分条件。如果数组是降序的你用假设升序的二分逻辑去查就会出问题如果数组存在重复元素求第一个等于x的位置和任意一个等于x的位置写出的二分边界完全不同。教科书上的二分示例几乎都是升序无重复数组考生习惯了这种天然设定但题目里并没有给出这些前提。3.2 复杂度表述量级和常数的区别判断题里嵌了一道关于斐波那契递归复杂度的题用不记忆化的递归函数计算第n个斐波那契数时间复杂度是O(2^n)。这道题是对的。设T(n)为调用次数有T(n) T(n-1) T(n-2) 1这个递推的解是指数级的。更精确地说复杂度约为O(1.618^n)它确实小于2^n所以ItsO(2^n)作为上界是正确的只是不算紧确界。考试里几乎不会要求区分到这一步按对处理即可。但由这道题引申出一个重要考点复杂度的上界和紧确界有什么区别。我建议七级考生记住说算法复杂度是O(x)意思是增长率不超过x量级说是Θ(x)意思是与x量级相当。判断题如果出现用递归算斐波那契复杂度是O(n²)这种离谱表述一眼就能排除但像O(2^n)这种宽松但正确的表述判断时就要果断判对。另一道复杂度判断题在一个有n个节点的二叉搜索树中最坏情况下查找一个元素的时间复杂度是O(n)。这道题也对。二叉搜索树的查找复杂度取决于树高。树平衡时树高O(log n)但如果插入顺序不当按升序依次插入节点树会退化成一条链树高就是n查找也就变成O(n)。教材讲BST时默认画理想平衡树导致考生误以为BST一定快——实际上普通BST最坏查找就是O(n)只有AVL、红黑树这类自平衡树才保证O(log n)。3.3 边界与定义空指针、空树、单节点这些盲区今年有一道判断题考了堆在一个小根堆中从任意一个非根节点开始沿着父指针一路向上走到根节点沿途经过的节点值一定是非递减的。答案是对的。小根堆的性质是父节点 子节点所以从子节点向上走父节点值总是小于等于当前节点从下往上整体就是非递减。考场上容易错的地方在于把非递减和递增混为一谈——包含相等情况的序列经常被表述为非递减这是一种温柔但有效的陷阱。还有一道关于递归的判断递归函数每一次调用都会在系统栈中分配新的栈帧所以递归层数过深可能导致栈溢出。答案是对。系统栈大小固定常见环境下默认通常为几MB级别每层递归调用都会压入新栈帧包括参数、返回地址、局部变量等。当递归深度达到一定程度时就可能触发栈溢出。这种题表面像常识但它要求考生从调用机制的角度解释为什么要避免过深递归而不仅仅是知道过深会崩。有考生看到系统栈三个字就蒙圈因为脑子里只有递归没有栈帧这两个概念这就是典型的定义理解不完整。4. 我的考场做题次序建议与检查策略4.1 客观题的节奏控制这是我长期带学生总结出的节奏屡试不爽选择题15题控制在20到25分钟内完成判断题10题控制在10到12分钟内。也就是说客观题总计35分钟左右解决给后面的编程题留出100分钟以上。GESP七级编程题通常是4道题量不小后两道经常是DP或图论非常耗时客观题一定不能拖太久。具体顺序上我的建议是从头做到尾但卡壳的题标记跳过最后回头再看。选择题设计上就是1到2分钟一道如果看了3分钟还无法确定说明这个知识点存在盲区先跳过才是最优解用序号在草稿纸上画个圈做完其余题目后再集中处理。判断题阅读量小平均每题1分钟足够。判断题最忌讳的是翻译——考生经常把题目里的话按自己的理解改写成另一个版本再判断。比如小根堆从任意节点向根走节点值非递减有人心里改写成小根堆从上到下节点值递增这两句意思完全不同前者对后者错。做判断题时必须逐字扣住题干不要自己脑补替换。4.2 草稿纸上的排除痕迹检查法这个技巧看起来简单实战价值却很高做选择题时不要只在选中的选项上打勾至少把每个选项为什么错用一两个词记在草稿纸上。原因有两个。第一强迫你验证所有选项而不是看A像对的就直接选A很多迷惑性题目就是利用这种心理设计的。第二收卷前若有剩余时间回看草稿纸上的排除记录一分钟就能重新确认每道题的选择依据比重新读题干快得多。平时刷题也可以养成这个习惯。我让学生做历年真题时每道选择题草稿区必须写排除B空间复杂度不是O(1)这类短句。积累一段时间后客观题正确率普遍有明显提升。5. 从这次考试反推七级考生接下来怎么学5.1 三个最值得警惕的薄弱环节把2025年3月这套客观题的常见丢分点汇聚起来我看到的高频薄弱环节有三个。第一图的存储结构与算法复杂度的对应关系。邻接矩阵、邻接表、DFS、BFS、Dijkstra七级考生几乎都学过但能把为什么邻接表DFS是O(nm)讲清楚的人不到一半。考试很少直接问DFS复杂度是多少而是把问题埋进遍历场景里你需要自己识别并给出答案。第二动态规划状态定义和转移方程的语义意识。LIS那道题会写代码的学生可能背得出代码但当代码变成四个转移方程选一个时很多人反而迷糊了。这暴露的是对算法的理解停留在背代码层面而不是理解状态层面。第三判断题里的语言精度。技术表述中的一定可能保证不保证最坏平均均摊这些词在考试里等于考点本身。刷题时遇到这些词要停下来划一划想想它们是否改变了句子的真假。5.2 从七级往八级迈进三件值得坚持的事从七级到八级知识体系是连贯的。七级考经典的DFS/BFS、DP入门LIS、背包类、贪心基本思想八级通常会进一步推图论最短路的综合应用、更复杂的DP模型区间DP、状压DP入门以及线段树、树状数组这类复杂数据结构。基于这次客观题传递出的倾向我建议备考八级的同学做三件事一是把每个算法的复杂度推导用文字写一遍不是为了应付考试而是真正理解为什么是这个量级二是DP专项训练从看题解转变为先自己设计状态和转移再和题解对拍三是每周固定留时间训练手推短代码找一段15行以内的C程序不用编译器直接在纸上推运行结果再上机验证。这三件事对应的是八级考试里真正拉开差距的能力不是知道用什么算法而是能在限时内确认一个算法为什么适用、复杂度是否可接受、边界条件怎么处理。最后说点个人的感受。这几年凡是客观题做得稳的学生往往不是语法最熟练的而是能把自己脑中的知识用精确语言讲出来的那批。选择和判断看似在考知识实际上是在考你的知识有没有模糊地带。备考时多问自己几个为什么比多刷十道题管用。如果你已经考完这一场不妨把错题对应的知识点记下来趁热打铁补掉它——这些模糊地带不管后面考八级还是参加其他比赛迟早都会再遇到。