决选投票算法代码问题:无限循环与索引越界排查
决选投票逻辑的问题排查与修复
原代码存在的核心问题
- 无限循环触发:
winner初始值为False,当设置为None时,not winner仍为True,循环不会终止;且当所有候选人得票均为1时,错误地将所有候选人加入排除列表,后续逻辑混乱导致无法跳出循环。 - 索引越界错误:当所有候选人被排除后,代码仍尝试访问空列表的
i[0]元素;且在处理排除候选人时,在for m in exclude循环内直接清空row和exclude,导致后续操作逻辑断裂。 - 得票统计与淘汰逻辑错误:遍历
row时重复统计同一候选人的得票数,导致exclude重复添加相同候选人;错误地将得票为1的候选人全部排除,而非淘汰得票最少的候选人。 - 数据修改风险:直接将
vote = voters,修改vote会同步改动原voters数据,导致后续轮次统计出错。
修复后的完整代码
def runoff(voters): # 复制选民数据,避免修改原输入 current_voters = [voter.copy() for voter in voters] total_voters = len(current_voters) # 初始化有效候选人集合 candidates = set() for voter in current_voters: candidates.update(voter) candidates = list(candidates) while True: # 统计当前所有选民的有效首选 current_votes = [] for voter in current_voters: if voter: current_votes.append(voter[0]) # 无有效选票时直接返回None if not current_votes: winner = None break # 统计各候选人得票数 vote_counts = {} for candidate in candidates: vote_counts[candidate] = current_votes.count(candidate) # 检查是否有候选人获得超过50%的选票 majority = total_voters / 2 for candidate, count in vote_counts.items(): if count > majority: winner = candidate break else: # 无胜者,找出得票最少的候选人(可能多个) min_votes = min(vote_counts.values()) to_exclude = [c for c, cnt in vote_counts.items() if cnt == min_votes] # 更新有效候选人列表 candidates = [c for c in candidates if c not in to_exclude] # 移除每个选民列表中已淘汰的候选人 for voter in current_voters: for excluded in to_exclude: if excluded in voter: voter.remove(excluded) # 所有候选人都被淘汰时终止循环 if not candidates: winner = None break continue break # 找到胜者,终止循环 print("The winner is: ", winner) return winner # 测试用例1 runoff([["dem", "ind", "rep"], ["rep", "ind", "dem"], ["ind", "dem", "rep"], ["ind", "rep", "dem"]]) # 测试用例2 runoff([["a", "c", "d", "e", "b"], ["e", "b", "d", "c", "a"], ["d", "e", "c", "a", "b"], ["c", "e", "d", "b", "a"], ["b", "e", "a", "c", "d"]])
修复说明
- 数据隔离:使用
current_voters = [voter.copy() for voter in voters]复制原数据,避免修改输入的原始选民列表。 - 正确的多数判定:用
count > total_voters / 2判断是否获得超过50%的选票,兼容奇偶选民数场景,避免原代码仅适用于偶数的局限。 - 精准淘汰逻辑:统计所有候选人得票数后,找出得票最少的候选人(可能多个)并排除,符合决选投票规则。
- 循环终止条件:处理了无有效候选人、无有效选票的情况,直接返回
None;找到胜者后立即终止循环,彻底解决无限循环问题。 - 索引安全:在访问选民首选前先判断列表是否为空,避免触发
IndexError。
内容的提问来源于stack exchange,提问作者Sergey
相关产品推荐
相关产品推荐

