哈希表长 $31$,按照下面的程序依次输入 $4\ 17\ 28\ 30\ 4$,则最后的 $4$ 存入哪个位置?( )
#include <iostream>
#include <string>
#include <cmath>
#include <vector>
using namespace std;
const int N = 31;
int htab[N], flag[N];
int main()
{
int n, x, i, j, k;
cin >> n;
for (i = 0; i < n; i++) {
cin >> x;
k = x % 13;
while (flag[k]) k = (k + 1) % 13;
htab[k] = x;
flag[k] = 1;
}
for (i = 0; i < N; i++)
cout << htab[i] << " ";
cout << endl;
return 0;
}别被表长31带偏,这道题核心就盯住哈希函数里的模13和线性探测。拿到输入序列,按代码逻辑一步步模拟:算出初始下标k,若flag[k]已置1就k=(k+1)%13循环探测,直到找到空位写入。最后问的是序列末尾那个4落到了哪个下标,只要把前几个数的探测过程推对,自然就能锁定答案。
最容易掉进两个坑:一是死记'哈希值等于下标'的模板,看到插4就下意识选4,完全没看代码里其实是模13再线性探测;二是把表长31当成探测范围,以为探测到13就绕回0,或者以为探测会遍历整个31长度的数组,结果算错下标。还有少数学生会把'最后的4'理解成数字4在序列里的最后一个副本,而忽略它实际被存到了哪个位置,导致选错项。
【考点与命题视角】 哈希表的存储与冲突处理是本次GESP七级的核心考点,具体涉及哈希函数的计算(取模)以及线性探测法解决冲突。命题人特意在代码中设置了两个干扰项:表长N=31和哈希函数中的模数13。这显然是为了测试学生是否真正读懂了代码逻辑,而不是机械地套用'哈希表下标=数据%表长'的模板。如果学生只看到表长31,很容易误以为探测范围是0~30,或者以为每次冲突后是k=(k+1)%31,从而算出完全错误的下标。这道题的陷阱就在于:哈希函数只用了13,探测也是模13循环,表长31在这里纯粹是个红鲱鱼(无关信息),只用来定义数组大小。
【概念梳理:人话版】 哈希表本质上就是个数组,用来快速存东西。但数组有固定长度,如果两个不同的数算出来的下标一样(冲突了),怎么办?代码里用的是'线性探测':算出初始下标k,如果这个位置已经被占用了(flag[k]为1),就把k加1再取模,继续往后找,直到找到一个空位置为止。取模13意味着探测范围只在0到12这13个格子循环,哪怕表长有31,多出来的格子也永远用不上。
【逐空推演:把过程跑一遍】 我们按代码逻辑,把输入序列4 17 28 30 4一个个插进去看:
1. 插入第一个4: * 计算初始下标:k = 4 % 13 = 4。 * 检查flag[4]:初始全是0,说明空。 * 写入:htab[4] = 4,flag[4] = 1。 * *结论:4落在了下标4。*
2. 插入17: * 计算初始下标:k = 17 % 13 = 4。 * 检查flag[4]:刚才插了4,现在是1,说明被占。 * 探测:k = (4 + 1) % 13 = 5。 * 检查flag[5]:是0,空。 * 写入:htab[5] = 17,flag[5] = 1。 * *结论:17落在了下标5。*
3. 插入28: * 计算初始下标:k = 28 % 13 = 2。 * 检查flag[2]:是0,空。 * 写入:htab[2] = 28,flag[2] = 1。 * *结论:28落在了下标2。*
4. 插入30: * 计算初始下标:k = 30 % 13 = 4。 * 检查flag[4]:被占(4)。 * 探测:k = 5。 * 检查flag[5]:被占(17)。 * 探测:k = 6。 * 检查flag[6]:是0,空。 * 写入:htab[6] = 30,flag[6] = 1。 * *结论:30落在了下标6。*
5. 插入最后一个4(题目问的就是这个): * 计算初始下标:k = 4 % 13 = 4。 * 检查flag[4]:被占(第一个4)。 * 探测:k = 5。 * 检查flag[5]:被占(17)。 * 探测:k = 6。 * 检查flag[6]:被占(30)。 * 探测:k = 7。 * 检查flag[7]:是0,空。 * 写入:htab[7] = 4,flag[7] = 1。 * *结论:最后的4落在了下标7。*
【避坑指南:为什么容易选错】 很多同学会直接选A(3)或者B(4)。选A的人通常是把'最后的4'理解成了'数字4在序列里的位置',或者误以为探测会一直往后推到31长度的边界;选B的人则是典型的'哈希值即下标'思维定势,看到插4就以为落4,完全忽略了前面的17、28、30已经把4、5、6占满了。这道题的题干问的是'最后的4存入哪个位置',这个'最后的'指的是输入序列中最后一个出现的4,而不是数字4本身。命题人故意用这个词制造歧义,就是为了筛选出那些真正读懂代码、能模拟执行流程的学生。
另外,还有一个隐藏坑:表长31。如果学生以为探测是k=(k+1)%31,那探测范围会扩大到27,结果完全不同。代码里明确写的是%13,这是硬性约束,必须严格遵守。
【考频与趋势分析】 从题库数据来看,哈希表相关的考点在GESP七级中属于高频考点。具体数据如下:
【预测】 基于2023-2026年的数据,哈希表/容器基础在七级中的考频持续走高,特别是2025年达到47题的峰值,2026年仍保持在37题的高位。这预示着未来几年,GESP七级对STL容器(哈希表、队列、栈等)的考察不会减弱,反而可能更加深入。预测方向如下: 1. 继续深挖线性探测与二次探测:像本题这样用模数制造冲突、用无关表长干扰的题目,未来仍会出现,但可能会增加探测次数的限制或更复杂的冲突解决策略(如二次探测),以区分不同层次的学生。 2. 结合其他容器:哈希表常与队列、栈或字符串处理结合,例如'用哈希表统计字符串出现频率'或'用队列模拟哈希表的插入过程',这类综合题在2025年已初现端倪,未来会更多。 3. 动态表长与扩容:虽然本题表长固定,但未来可能会出现动态扩容的哈希表题目,考察学生理解哈希表增长机制的能力。
总之,这道题是典型的'小步子、大陷阱',只要你能把代码逻辑跑通,答案自然浮现。记住:哈希表不是背公式,是看代码!