
2025年6月的GESP认证C八级依然是很多选手关注度最高的一组。我在考场外等朋友的时候顺手把选择题和判断题按回忆整理了一遍。说实话这张卷子的客观题部分没有特别偏的题但对基础概念的精细程度要求很高树状数组的复杂度、并查集的摊还分析、KMP的前缀函数、Dijkstra堆优化的先决条件、状态压缩DP的适用范围……基本都在考纲里扎扎实实地过了一遍。这篇文章把这部分题目和我的解析完整放出来题号顺序可能与原卷不完全一致答案也以官方最终发布为准。如果你今年要冲八级这份题解能帮你快速定位薄弱点如果你只是好奇八级到底考什么也可以把它当成一份考情地图来读。1. 2025年6月GESP C八级试卷整体观感1.1 选择题和判断题考了什么从整体看这次八级客观题仍然延续了“基础概念为主、算法性质为辅、少量计算题拉分”的风格。判断题更偏向概念真伪比如最小生成树的唯一性、Dijkstra是否能处理负权边、拓扑排序是否唯一、哈希表装填因子对性能的影响选择题则集中在线段树、树状数组、并查集、最短路、动态规划、栈、二叉树遍历、KMP这些经典知识点上。值得注意的是卷子里有好几道题都在考同一个底层逻辑某个算法在极端输入下还成立吗比如Dijkstra遇到负权边、快速排序每次分区都选到最值、0/1背包内层循环如果不倒序遍历会变成什么。这类题目并不要求你默写代码而是要求你真正理解算法为什么对、什么时候会失效。备考八级不能只停留在“能写出来”的层面必须能把复杂度、适用条件、边界情况都讲清楚。1.2 关于“回忆版题解”的说明以下所有题目都是考生回忆的转述不是试卷原图个别选项顺序可能打乱。我尽量把每个选项的来龙去脉写成完整解析而不只是给一个答案。对于有争议的说法我会额外说明判定依据。比如完全二叉树的高度不同教材可能按“层数”或“边数”定义GESP通常默认按层数计算这类细节在读题时一定要注意。2. 判断题题解共10题2.1 判断题第1~5题第1题一棵有n个结点的完全二叉树n≥1的高度为⌊log₂ n⌋1。答案正确。解析完全二叉树按层数计算高度时根结点的高度记为1。对一棵完全二叉树前h-1层是满的最后一层不一定满但结点数n一定满足2^(h-1) ≤ n ≤ 2^h - 1。两边取对数后h的最小值就是⌊log₂ n⌋1。例如n1时⌊log₂1⌋0高度为1n3时⌊log₂3⌋1高度为2符合三层?实际3个结点的完全二叉树可以放在两层根加两个叶子层数就是2。这个考点本身不难但要注意区分“边数高度”和“层数高度”如果按边数定义答案需要减1。GESP题目中一般不会故意在这种定义上设坑但读题要仔细。第2题在连通无向图中若所有边的权值互不相同则最小生成树唯一。答案正确。解析最小生成树唯一的充分条件之一就是所有边权互异。原因是Kruskal算法按权值从小到大选边Prim算法也依赖边权比较当所有边权都不同时每一步“当前最小可用边”都是唯一的贪心选择没有二义性。反过来如果存在权值相同的边最小生成树可能不唯一。例如三个点构成三角形三条边权分别为1、1、2最小生成树可以选择两条权为1的边中的任意一条这就是两种不同的生成树。很多考生只记住“MST不唯一”这个结论却忽略了互异权值是唯一性的一个充分条件这道题就是专门考这个边界。第3题对n个元素的数组进行冒泡排序最坏情况下的交换次数为n(n-1)/2。答案正确。解析冒泡排序的最坏情况是输入完全逆序。此时每一对逆序元素最终都会被交换一次交换次数等于数组的逆序对总数而n个元素最多有n(n-1)/2个逆序对。例如n4数组4,3,2,1第一轮交换三次后变成3,2,1,4第二轮交换两次第三轮交换一次累计6次正好等于4×3/2。注意比较次数也是n(n-1)/2但有些教材的冒泡排序做了提前结束优化这并不影响最坏情形。考试中如果出现“平均”而不是“最坏”结果不同但这里写得很明确。第4题使用邻接矩阵存储稀疏图时遍历所有边的时间复杂度是O(n²)。答案正确。解析邻接矩阵不管有多少条实际存在的边都需要用n×n的矩阵表示所有可能的边。遍历“所有边”意味着要扫描整个矩阵判断每个位置是否为有效边因此时间复杂度是O(n²)。对于稀疏图m远小于n²用邻接表遍历所有边只需要O(nm)显然更高效。这道题其实是在考“存储结构决定遍历成本”的思想。很多人在学习图结构时只记邻接矩阵适合稠密图、邻接表适合稀疏图但未必清楚具体复杂度这次判断题直接把结论拿出来问容易丢分。第5题在C中表达式5 1的结果为1按位与运算可用于判断整数奇偶性。答案正确。解析二进制下奇数的最后一位是1偶数的最后一位是0因此任意整数x与1做按位与x1等于x的二进制最低位。5的二进制是101最低位是1所以51结果为1。判断奇偶性时x11表示奇数x10表示偶数。相比取模运算x%21位运算通常更快但不建议为了可读性牺牲。八级不考太底层的东西但位运算是状态压缩DP的基础所以这种小题往往是在为后面的状压题做铺垫。2.2 判断题第6~10题第6题KMP算法中模式串长度为m文本串长度为n匹配过程中文本串下标只会向前移动不会回溯。答案正确。解析KMP算法的核心优势就是文本串指针i始终不后退。当某一位失配时模式串指针j根据next数组回退到合适位置然后继续用当前文本串位置与新的模式串位置比较。也就是说文本串从头到尾最多扫描一遍模式串回退的总次数又受m限制因此总时间复杂度为O(nm)。如果不理解“文本串不回退”就很难理解为什么KMP能在线性时间内完成匹配。这道判断题属于最基础的原理确认题但也是很多人的知识盲区因为大家往往只背代码没有把指针移动过程在纸上画通。第7题Dijkstra算法可以用于有负权边的图只要图中没有负权环。答案错误。解析Dijkstra算法基于贪心思想每次从优先队列中取出当前距离最小的顶点并认为它的最短距离已经确定。但有负权边时后面可能出现一条权值为负的边让某个已经确定“最短”的顶点的距离变得更小此时贪心决策就失效了。即使图中没有负权环Dijkstra也不保证正确。例如A到B权为2A到C权为0C到B权为-3Dijkstra会先确定B的距离为2但实际最短路径是A→C→B距离为-3显然错误。要处理负权边应该使用Bellman-Ford或SPFA。这道题几乎是八级必考陷阱一定要记牢。第8题哈希表装填因子较大时性能下降不明显。答案错误。解析装填因子定义为表中已有元素个数除以桶的个数它直接反映冲突概率。装填因子越大桶内元素越多查找时需要在冲突链表或探测序列中比较的次数越多。在链地址法下平均查找长度会随着装填因子的增大而线性上升最坏情况甚至退化为O(n)。所以当装填因子超过阈值时哈希表需要扩容并重新哈希。很多考生只记得哈希表“平均O(1)”的优点忽略了它建立在合理装填因子和良好散列函数的前提上。这种判断题就是提醒你任何数据结构的复杂度优势都是有限定条件的。第9题一个有向无环图DAG的拓扑排序结果一定是唯一的。答案错误。解析拓扑排序每次从当前入度为0的顶点中选一个输出如果某一时刻入度为0的顶点不止一个选择不同的顶点就会得到不同的合法序列。比如三个顶点1、2、3只有边1→2和1→3入度为0的顶点是1但输出1后2和3同时入度为0可以先2后3也可以先3后2。因此DAG的拓扑排序不一定唯一。只有当图中所有顶点都有严格的前后依赖关系也就是任意两个顶点之间都存在一条路径时拓扑排序才唯一。这种结论在判断图中是否有环的题目里经常被混着考需要特别小心。第10题状态压缩动态规划通常用于解决状态数量较小、可以用一个整数表示集合的优化问题常见于n≤20左右的集合覆盖、TSP等场景。答案正确。解析状态压缩DP的核心是把一个集合的选取情况编码成二进制整数用位运算快速转移。比如n个点的TSP状态可以表示为“已经访问过的顶点集合当前所在顶点”总共n×2^n个状态。n20时2^20约100万配合n的转移可以接受n40时2^40就不可能直接枚举了。所以题干说“n≤20左右”是符合实际经验的。八级的编程题里状态压缩DP出现频率不低判断题考适用场景其实是给考生提个醒状压不是万能的要会识别题目规模。3. 选择题题解共18题3.1 选择题第1~6题数据结构与图论第1题已知二叉树的前序遍历序列为ABDCE中序遍历序列为DBACE其后序遍历序列是A. DBEACB. DBECAC. DEBCAD. DABEC答案B。解析前序遍历的第一个结点A是根中序遍历中A左边是DB右边是CE所以左子树包含D、B右子树包含C、E。再看前序遍历紧跟A的B说明B是左子树根中序中B左边是D所以D是B的左孩子。右子树前序为CE中序为CE说明C是右子树根E是C的右孩子。后序遍历先左后右再根左子树为DB右子树为EC最后是A因此答案是DBECA。这类题必须自己画一遍树如果只背“前序找根、中序分左右”的流程很容易在左右子树顺序上出错。第2题一棵完全二叉树共有1023个结点其中叶子结点的个数是A. 256B. 511C. 512D. 1024答案C。解析1023恰好等于2^10-1说明这是一棵满二叉树最后一层全部填满共有10层。满二叉树第10层的结点数就是叶子数等于2^9512。即使不是满二叉树也可以用公式计算设n为结点数叶子数等于n - 完全二叉树中度数为2的结点数这个结论推导较麻烦。考场上一眼看出2^10-1的形式是最快的方法。如果题目给1000这种不整的数更稳妥的做法是先用高度公式确定层数再算最后一层和倒数第二层的叶子数量。第3题树状数组支持单点修改和前缀和查询单次操作的时间复杂度是A. O(1)B. O(log n)C. O(√n)D. O(n)答案B。解析树状数组利用lowbit操作把区间信息按二进制分块存储。单点更新时从当前下标i开始不断执行i i (-i)直到超过n前缀查询时从当前下标i开始不断执行i - i (-i)直到变为0。两个过程循环的次数都等于i的二进制表示中1的个数最多不超过log₂n因此单次操作O(log n)。树状数组代码短、常数小但它不能像线段树那样灵活处理区间修改和区间查询这也是GESP八级同时考两者的原因要知道各自的优缺点。第4题并查集同时使用路径压缩和按秩合并后执行m次查找或合并操作的总时间复杂度约为A. O(m log n)B. O(m α(n))C. O(m n)D. O(m)答案B。解析路径压缩让每个结点直接指向根按秩合并让树的高度尽可能小两者结合后单次操作的摊还时间复杂度是反阿克曼函数α(n)的级别。α(n)增长极其缓慢对于所有实际规模的n都可以看作常数所以常常被表述为“近似O(1)”。注意如果只使用路径压缩而不按秩合并最坏情况下单次操作仍可能是O(log n)如果只用按秩合并而不路径压缩树高也是O(log n)。只有两个优化同时使用才能达到α(n)这个几乎线性的复杂度。这道题从复杂度角度区分了不同实现比单纯考“并查集能查环”更有深度。第5题用优先队列优化Dijkstra算法有V个顶点、E条边时间复杂度为A. O(V²)B. O(E log V)C. O((VE) log V)D. O(VE)答案C。解析堆优化Dijkstra中每个顶点可能因松弛操作多次入堆最坏情况下每条边都会触发一次更新因此入堆和出堆操作的总次数是O(E)级别每次堆操作O(log V)此外每个顶点至少从堆中取一次共V次每次也是O(log V)。合起来是O((VE) log V)。如果使用朴素数组找最小值不依赖堆复杂度是O(V²)适合稠密图。很多教材会简写为O(E log V)但这默认了V不会成为主导项严格写法还是(VE)log V。考场上要能识别各种等价写法。第6题快速排序在最坏情况下的时间复杂度是A. O(n log n)B. O(n²)C. O(n)D. O(log n)答案B。解析快速排序之所以平均复杂度是O(n log n)是因为每次划分都能把区间大致分成两半。但如果每次选中的基准值都是当前区间的最小值或最大值划分后一个区间为空另一个区间只比原来少一个元素递归深度变成n每一层划分需要扫描整个区间O(n)总复杂度就是O(n²)。这种情况常见于原数组已经有序且基准值固定取第一个元素时。C标准库的sort内部使用内省排序它会检测递归深度过深并转成堆排序所以实际使用中很少退化但作为算法分析题最坏复杂度必须答O(n²)。3.2 选择题第7~12题算法分析与动态规划第7题关于拓扑排序下列说法正确的是A. 拓扑排序可以求出有向图的最长路径B. 若拓扑排序成功则图中一定不存在环C. 任意有向图的拓扑排序结果一定唯一D. 拓扑排序只能用于无向图答案B。解析拓扑排序的核心操作是反复删除入度为0的顶点。如果某一时刻图中还有剩余顶点但所有顶点的入度都大于0说明这些顶点之间形成了一个环无法继续排序。因此一个图能完成拓扑排序当且仅当它是有向无环图B正确。拓扑排序结果的唯一性取决于入度为0顶点的选择顺序不一定唯一C错。拓扑排序和有向图的最长路径也没有直接关系虽然DAG最长路径可以用动态规划求解但那不是拓扑排序本身的功能A错。这个选项看起来很有迷惑性要特别留意。第8题模式串为ababa若使用KMP算法整个模式串的最长公共前后缀长度为A. 1B. 2C. 3D. 4答案C。解析最长公共前后缀指字符串的一个真前缀同时是它的后缀且不能取整个字符串本身。对ababa来说前缀有a、ab、aba、abab后缀有a、ba、aba、baba其中相同且最长的是aba长度为3。注意abab不是后缀baba也不是前缀。这个值对应KMP中前缀函数数组的最后一个元素pi[4]3。KMP失配时跳转的依据就是当前已匹配部分的最长公共前后缀长度所以把前缀函数理解透彻比记住next代码重要得多。第9题标准0/1背包问题n件物品背包容量为W使用滚动数组优化空间后时间复杂度与空间复杂度分别是A. O(nW)O(nW)B. O(nW)O(W)C. O(n²)O(W)D. O(n log W)O(W)答案B。解析二维0/1背包的状态转移是dp[i][j]max(dp[i-1][j], dp[i-1][j-w]v)其中i是物品编号j是容量。由于每一层只依赖上一层可以只用一维数组dp[j]表示容量为j时的最大价值。时间上仍然要对n件物品和W个容量各做一次转移所以时间复杂度O(nW)空间上只需要W1长度的数组所以O(W)。实现时内层循环必须从W到w[j]倒序遍历否则一个物品会被多次放入变成完全背包。这个考点几乎每次八级都会出现属于必得分。第10题定义函数f(n)当n≤1时返回1否则返回f(n-1)f(n-2)那么f(6)的值是A. 8B. 10C. 13D. 21答案C。解析按递推关系逐步计算。f(0)1f(1)1f(2)f(1)f(0)2f(3)f(2)f(1)3f(4)f(3)f(2)5f(5)f(4)f(3)8f(6)f(5)f(4)13。这个递推和斐波那契数列很像只是初始值略有不同。直接递归计算f(50)会产生大量重复子问题时间复杂度是指数级的所以实际应用中要改成记忆化搜索或动态规划。GESP八级经常在客观题里用这种小规模递归考查递推基础同时也暗示了“为什么需要DP”。第11题n个顶点的有向完全图边的总数是A. n(n-1)/2B. n(n-1)C. n²D. n(n1)/2答案B。解析有向完全图规定任意两个不同顶点之间都存在两条方向相反的弧。从n个顶点中任选两个顶点组合数是C(n,2)n(n-1)/2但每一对会产生2条有向边所以总边数是n(n-1)。无向完全图才是n(n-1)/2。这个选项设计很典型就是把无向完全图的公式和有向完全图的公式放一起稍微走神就会选错。类似的还有“有向完全图每个顶点的出度是n-1入度也是n-1”可以互相验证。第12题入栈序列为1、2、3、4下列出栈序列中不可能的是A. 1 2 3 4B. 1 4 3 2C. 3 4 1 2D. 4 3 2 1答案C。解析模拟每个选项。A每入一个就弹一个当然可能。B先入1并弹出1再入2、3、4弹出4、3、2即可。D全部入栈后依次弹出得到4、3、2、1。C的问题在于要让3第一个出栈必须先入1、2、3然后弹出3此时栈内自顶向下是2、1。接着入4如果弹出4下一个能弹出的只能是2不可能是1因为1被2压在下面。所以3 4 1 2不可能。做这类题推荐用笔在纸上维护一个栈不要靠直觉判断。栈相关的序列题是八级送分题但也是最容易在草稿上翻车的题。3.3 选择题第13~18题计数与综合应用第13题下列排序算法中不稳定的是A. 冒泡排序B. 插入排序C. 选择排序D. 归并排序答案C。解析排序的稳定性指相同关键字的元素在排序后能否保持原本的相对顺序。冒泡、插入、归并都容易实现成稳定排序。选择排序每一轮找到未排序部分的最小值然后与当前位置交换。如果这个最小值在待排序区间中有多个相等元素交换可能会把靠前的相同元素换到后面破坏稳定性。举例[5a, 2, 5b, 1]第一轮找到最小值1与第一个元素5a交换得到[1, 2, 5b, 5a]原本在前的5a跑到了5b后面不稳定。快排的经典实现也不稳定但本题没有给出这个选项选C即可。这种题考查的是对排序算法底层交换过程的理解。第14题使用欧几里得算法求gcd(2025, 750)结果是A. 15B. 25C. 75D. 150答案C。解析欧几里得算法反复用较大数模较小数。2025 mod 750 525750 mod 525 225525 mod 225 75225 mod 75 0因此最大公约数是75。也可以分解质因数20253^4×5^27502×3×5^3公共部分为3×5^275。GESP考数论时一般不会太难但辗转相除法的过程必须熟练因为它在编程题里会以“快速幂最大公约数”的组合形式出现。这类题建议在草稿上写完整列式不要心算太大数字。第15题5件不同的奖品分给3个人每个人可以拿多件也可以不拿分配方案数是多少A. 3⁵B. 5³C. C(8,3)D. 2⁵答案A。解析因为奖品是不同物品每一件奖品都有3种选择给第1人、给第2人、给第3人。5件奖品的选择相互独立所以总方案数是3×3×3×3×33^5243。如果把“5件相同奖品分给3个人允许有人空手”这样隔板法问题混进来答案就会不同那是C(7,2)之类的组合数。区分“相同物品”和“不同物品”是计数题的第一原则。这道题本质上考乘法原理是八级组合数学的基础部分。第16题用数组存储一棵完全二叉树根结点下标为1。若某结点下标为12则其父结点下标是A. 5B. 6C. 7D. 8答案B。解析完全二叉树用数组存储时如果下标从1开始结点i的左孩子下标为2i右孩子下标为2i1父结点下标为i/2整除。12/26所以父结点下标是6。这类题反向也经常考已知父结点下标i求孩子下标。注意如果下标从0开始公式会变成2i1和2i2父结点是(i-1)/2。很多人在考试时没有注意“根结点下标为1”这个条件直接套0下标公式导致错误。GESP的题很喜欢在这种细节上埋点。第17题线段树维护数组区间最小值单次区间查询的时间复杂度为A. O(1)B. O(log n)C. O(n)D. O(n log n)答案B。解析线段树的区间查询会把目标区间递归地分解成若干完全覆盖的结点。虽然看起来可能需要访问很多结点但每一层上最多只有两个边界结点会被部分访问其他访问的都是完整结点所以被访问的结点总数是O(log n)级别。这也是线段树相比暴力的核心优势。线段树的建树是O(n)单点修改是O(log n)区间查询是O(log n)。如果遇到需要区间加、区间乘、区间赋值等懒标记操作复杂度仍然是O(log n)但常数会变大。八级客观题常问复杂度理解“为什么是log n”比记住结论更稳妥。第18题一个有n个顶点、m条边的有向图用邻接表存储从某个顶点出发执行深度优先搜索时间复杂度为A. O(n)B. O(m)C. O(nm)D. O(nm)答案C。解析DFS每个顶点最多被访问一次每次从顶点出发都要扫描它的邻接表扫描邻接表的总次数等于图中所有边的数量。每个顶点访问是O(n)每条边检查是O(m)所以总时间O(nm)。空间上需要记录每个顶点是否访问过O(n)递归栈深度最坏O(n)。如果图用邻接矩阵存储DFS复杂度则会是O(n²)。同一算法在不同存储结构下的差异是GESP高频考点考场上要看清题干是“邻接表”还是“邻接矩阵”。4. 高频考点与备考建议4.1 八级常考的知识点清单根据这次真题的回忆我把客观题涉及的知识点整理成了一个速查表适合冲刺阶段每天过一遍知识点常见考法需要掌握的细节树状数组单点修改、前缀查询复杂度lowbit运算、为什么是O(log n)线段树区间查询、区间修改复杂度懒标记、递归分解思想并查集判环、连通性、复杂度路径压缩、按秩合并、反阿克曼函数KMP前缀函数、失配跳转文本串不回溯、next数组含义最短路Dijkstra、Bellman-Ford适用条件负权边是否合法、堆优化复杂度最小生成树Kruskal、Prim、唯一性边权互异时唯一、算法选择依据拓扑排序判环、结果唯一性入度队列、DAG性质动态规划0/1背包滚动数组、状态转移内层倒序遍历、滚动数组压缩空间状态压缩DP集合状态表示、n≤20规模位运算、状态转移方式二叉树遍历序列复原、完全二叉树前中后序关系、数组存储下标公式栈进出栈序列合法性栈顶元素顺序、模拟过程排序稳定性、最坏/平均复杂度选择排序不稳定、快排最坏退化数论最大公约数、质因数分解辗转相除法、计数原理组合计数乘法原理、隔板法物品是否相同、是否允许空手哈希表冲突处理、装填因子平均与最坏复杂度差异这张表并不需要逐条背诵而是在刷题后用来“对标”自己的盲区。如果你看到某一行毫无感觉说明对应的专题还没完全吃透。4.2 最后30天怎么刷题备考GESP八级只刷编程题是不够的。客观题考查的知识点很细而且很多是“结论的反面”比如最小生成树唯一性的充分条件、Dijkstra的负权限制。这些在编程题里不太容易暴露因为你会选择合适的算法去套但在判断题里错误选项就是要你识别这些边界。我建议把最后一个月分成三个阶段第一个十天按专题过知识点每学完一个算法就手写复杂度证明和适用条件第二个十天每天做一套类似GESP八级的选择题和判断题限时20分钟完成然后对错题写“为什么错、正确说法是什么、能不能举反例”最后十天回归编程题但每做完一道题都要在代码注释里写出算法复杂度和边界条件。这样做的好处是客观题的正确率会直接反哺你的编程题因为你更清楚自己写的代码为什么成立。4.3 常见丢分点与现场策略从这次回忆题里能明显看到几个高频丢分点。第一把Dijkstra当成万能最短路算法忽略负权边第二认为连通无向图的最小生成树只要所有边权互异就唯一这个结论是对的但很多人反过来把“权值相同就必然不唯一”也当成绝对结论其实有可能唯一第三KMP的next值算错主要是没有区分“最长公共前后缀”和“失配后跳转位置”两个概念第四0/1背包滚动数组的遍历方向记反这在代码题里直接致命第五拓扑排序唯一性被误判因为默认“从小的开始取”就以为只有一种结果。现场做题时判断题遇到不确定的说法可以先举一个小例子验证。比如判断“DAG的拓扑排序唯一”画一个1→2和1→3马上就知道是错的。选择题如果计算量大比如二叉树遍历的复原务必在草稿纸上真正画出树不要只靠脑中想象。客观题建议控制在15到20分钟如果某道题卡住超过2分钟先标记跳过最后再回头算。最后说点我自己的体会。很多考生考完八级只抱怨编程题难但真正决定能不能拿优秀等级的往往是前面这20多道客观题。我在备考时把每一道选择题都当成一个小项目来做不只看选项而是把每个错误选项改成正确说法再想一个反例。这个方法看起来慢但对概念的烙印特别深。今年六月的题目里至少有五六道都在考同一个逻辑——这个算法在极端情况下还成立吗如果你也打算冲八级不妨把这套题解里的每一行都自己动手推一遍而不是直接背答案。