多数票制 - CS50x 2026
待解决的问题
选举形式多种多样。在英国,首相由君主任命,通常选择在下议院获得席位最多的政党的领袖。美国则使用多步骤的选举人团程序,由公民投票决定各州如何分配选举人票,再由选举人选出总统。
然而,最简单的选举方式或许是通常被称为“多数票制”(plurality vote)的方法(也称为“简单多数制”或“胜者全得”)。在多数票制中,每位选民只能投给一位候选人。在选举结束时,获得票数最多的候选人即被宣布为选举获胜者。
在本项目中,你将实现一个运行多数票制选举的程序,如下所述。
演示
分发代码
在本项目中,你将扩展由 CS50 工作人员提供的“分发代码”的功能。
下载分发代码
登录 cs50.dev,点击终端窗口,并执行 cd 命令。你应该会发现终端窗口的提示符如下所示:
$
接下来执行
wget https://cdn.cs50.net/2026/x/psets/3/plurality.zip
以便将名为 plurality.zip 的压缩包下载到你的 codespace。
然后执行
unzip plurality.zip
创建一个名为 plurality 的文件夹。你不再需要该 ZIP 文件,因此可以执行
rm plurality.zip
并在提示符处输入 “y” 后按 Enter 键,以删除你下载的 ZIP 文件。
现在输入
cd plurality
后按 Enter 键进入(即打开)该目录。你的提示符现在应如下所示。
plurality/ $
如果一切顺利,执行
ls
你应该看到一个名为 plurality.c 的文件。执行 code plurality.c 应打开该文件,你将在此文件中编写本问题集的代码。如果没有,请回顾你的步骤,看看能否确定哪里出了问题!
理解 plurality.c 中的代码
每当你扩展现有代码的功能时,最好先确保你理解它当前的状态。
首先看文件顶部。#define MAX 9 这行语法表示 MAX 是一个常量(等于 9),可以在整个程序中使用。在这里,它代表选举可以拥有的最大候选人数量。
// Max number of candidates
#define MAX 9
注意 plurality.c 随后使用该常量定义了一个全局数组——也就是说,任何函数都可以访问的数组。
// Array of candidates
candidate candidates[MAX];
但是,在这种情况下,什么是 candidate 呢?在 plurality.c 中,candidate 是一个结构体(struct)。每个 candidate 有两个字段:一个名为 name 的 string,代表候选人的姓名;一个名为 votes 的 int,代表候选人获得的票数。
// Candidates have name and vote count
typedef struct
{
string name;
int votes;
}
candidate;
现在,看看 main 函数本身。看看你是否能找到程序设置全局变量 candidate_count 的位置,它代表选举中的候选人人数。
// Number of candidates
int candidate_count;
那么,在哪里将命令行参数复制到 candidates 数组中呢?
// Populate array of candidates
candidate_count = argc - 1;
if (candidate_count > MAX)
{
printf("Maximum number of candidates is %i\n", MAX);
return 2;
}
for (int i = 0; i < candidate_count; i++)
{
candidates[i].name = argv[i + 1];
candidates[i].votes = 0;
}
又是在哪里要求用户输入选民人数的呢?
int voter_count = get_int("Number of voters: ");
然后,程序让每位选民输入一张选票,并为每位被投票的候选人调用 vote 函数。最后,main 调用 print_winner 函数来打印选举的获胜者(或多位获胜者)。我们将把识别实现这些功能的代码的任务留给你。
但是,如果你进一步查看文件下方,你会注意到 vote 和 print_winner 函数留空了。
// Update vote totals given a new vote
bool vote(string name)
{
// TODO
return false;
}
// Print the winner (or winners) of the election
void print_winner(void)
{
// TODO
return;
}
这部分由你来完成!除了 vote 和 print_winner 函数的实现(以及根据需要包含额外的头文件)之外,你不应修改 plurality.c 中的任何其他内容。
提示
点击下面的切换按钮阅读一些建议!
完成 vote 函数
接下来,完成 vote 函数。
- 考虑
vote的函数签名bool vote(string name),显示它接受一个名为name的string参数,代表被投票的候选人姓名。 vote应返回一个bool值,其中true表示投票成功,false表示投票失败。
解决这个问题的一种方法是执行以下操作:
遍历每位候选人
检查候选人的姓名是否与输入
name匹配- 如果是,增加该候选人的票数并返回
true - 如果否,继续检查
- 如果是,增加该候选人的票数并返回
如果检查完每位候选人后都没有匹配项,返回
false
让我们写一些伪代码来提醒你这样做:
// Update vote totals given a new vote
bool vote(string name)
{
// 遍历每位候选人
// 检查候选人姓名是否与给定姓名匹配
// 如果是,增加候选人的票数并返回 true
// 如果没有匹配项,返回 false
}
不过,代码实现将留给你来完成!
完成 print_winner 函数
最后,完成 print_winner 函数。
- 该函数应打印出在选举中获得最多票数的候选人的姓名,然后打印一个换行符。
- 如果多位候选人各自拥有最高票数,选举可能会以平局告终。在这种情况下,你应该输出每位获胜候选人的姓名,每人占一行。
你可能会认为排序算法是解决这个问题的最佳方案:想象一下按票数总计对候选人进行排序,并打印排在首位的候选人(或多位候选人)。但请记住,排序可能开销很大:即使是 Merge Sort(最快的排序算法之一),运行时间也需要 \(O(N \space log(N))\)。
考虑一下,你只需要两条信息就能解决这个问题:
- 最高票数
- 获得该票数的候选人(或多位候选人)
因此,一个好的解决方案可能只需要两次搜索。写一些伪代码来提醒自己这样做:
// Print the winner (or winners) of the election
void print_winner(void)
{
// 找到最高票数
// 打印获得最高票数的候选人(或多位候选人)
}
不过,代码将留给你来完成!
视频讲解
如何测试
确保测试你的代码,以确保它可以处理……
- 包含任意数量候选人的选举(最多为
MAX值9) - 按姓名投票给候选人
- 对不在选票上的候选人进行无效投票
- 如果只有一名获胜者,打印选举的获胜者
- 如果有多名获胜者,打印选举的获胜者
正确性
check50 cs50/problems/2026/x/plurality
风格
style50 plurality.c
如何提交
在你的终端中,执行以下命令来提交你的作品,并回答出现的提示。
submit50 cs50/problems/2026/x/plurality