CS50 Tideman平局场景counter初始化位置致测试失败问题
Tideman选举print_winner计数器初始化位置问题解析
核心原因是计数器的重置规则和统计逻辑不匹配,和作用域对应的变量生命周期机制直接相关:
- 当
int counter = 0声明在外层for循环外部时,这个变量的生命周期覆盖整个print_winner函数的执行全程,只会在函数刚启动时被赋值为0一次。后续遍历每一位候选人做统计时,counter不会清零,会持续累加之前所有候选人统计过程中攒下的数值。 - 当
int counter =0声明在外层for循环内部时,每一轮循环切换到新的候选人、进入循环体作用域时,counter都会被重新创建并初始化为0,上一轮候选人统计留下的计数值会被直接丢弃,完全服务于当前候选人的独立统计。
平局场景触发校验失败的具体逻辑
Tideman算法判断胜者的规则是:不存在任何其他候选人j能击败i(即对所有j,locked[j][i] == false),此时i就是最终胜者。你的统计逻辑是对每个i,数有多少个j满足locked[j][i] == false,数到总数等于候选人数量时就判定i为胜者。
如果counter不重置,前一个候选人统计得到的计数值会被带到下一个候选人的统计流程里:比如3个候选人的场景,统计第一个候选人时counter累计到2(还差1个到阈值3),切换到第二个候选人统计时,counter从2开始计数,只要碰到第一个满足locked[j][i] == false的项(平局场景下这类false项比无平局场景更多),counter就会凑够3,直接把当前候选人误判为胜者,哪怕这个候选人实际有被其他人击败的记录,自然无法通过平局场景的校验用例。
错误写法参考
无法通过用例的写法核心逻辑如下:
void print_winner(void) { int counter = 0; // 仅在函数启动时初始化一次 for (int i = 0; i < candidate_count; i++) { // 无counter重置逻辑,残留上一个候选人的统计值 for (int j = 0; j < candidate_count; j++) { if (locked[j][i] == false) { counter++; // 累加残留值后极易误判阈值 if (counter == candidate_count) { printf("%s\n", candidates[i]); } } } } return; }
你之前查到的「循环内部声明变量有最小作用域」不是空规则:C语言里进入变量所在的作用域时会创建变量、执行初始化,离开作用域时变量就会被销毁,旧值不会保留。把counter放在外层循环内部,刚好利用这个机制自动完成每轮统计前的计数器清零,完全匹配「每个候选人独立统计被击败情况」的需求。
内容的提问来源于stack exchange,提问作者beginner
相关产品推荐
相关产品推荐

