多数制
要解决的问题
选举有各种形式和规模。在英国,首相由君主正式任命,君主通常会选择在下议院赢得最多席位的政党领导人。美国使用多步骤的选举人团流程,公民投票决定每个州如何分配选举人,然后由选举人选举总统。
不过,也许最简单的选举方式是一种通常被称为”多数制投票”的方法(也称为”简单多数制”或”赢者通吃”)。在多数制投票中,每位选民投票给一位候选人。选举结束时,得票最多的候选人被宣布为选举的获胜者。
对于这个问题,你将实现一个程序来运行多数制选举,如下图所示。
演示
分发代码
对于这个问题,你将扩展由 CS50 工作人员提供的”分发代码”的功能。
下载分发代码
登录 cs50.dev, 点击你的终端窗口,然后执行 cd 本身。你应该会发现你的终端窗口’s prompt 类似于下面所示:
$
接下来执行
wget https://cdn.cs50.net/2026/x/psets/3/plurality.zip
以便将一个名为 plurality.zip 的 ZIP 文件下载到你的代码空间中。
然后执行
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)
{
// Iterate over each candidate
// Check if candidate's name matches given name
// If yes, increment candidate's votes and return true
// If no match, return false
}
不过,用代码实现的部分就交给你了!
完成 print_winner 函数
最后,完成 print_winner 函数。
- 该函数应输出选举中获得最多票数的候选人的姓名,然后输出一个换行符。
- 如果有多位候选人都获得了最多票数,选举可能以平局结束。在这种情况下,你应该输出每位获胜候选人的姓名,分别放在不同的行上。
你可能认为排序算法最能解决此问题:想象一下按票数对候选人进行排序,然后输出得票最多的候选人或各位候选人。不过,回想一下,排序可能开销很大:即使是归并排序——最快的排序算法之一——运行时间复杂度也是 O(N log(N))。
考虑一下,解决此问题你只需要两条信息:
- 最高票数
- 拥有该票数的候选人(或各位候选人)
因此,一个好的解决方案可能只需要两次搜索。写一些伪代码来提醒自己做这件事:
// Print the winner (or winners) of the election
void print_winner(void)
{
// Find the maximum number of votes
// Print the candidate (or candidates) with maximum votes
}
不过,代码实现就交给你了!
讲解视频
如何测试
请务必 测试你的代码以确保 it handles…
- 任意数量候选人的选举 (up to the
MAXof9) - 按姓名投票给候选人
- 投票给不在选票上的候选人的无效投票
- 如果只有一位获胜者,输出选举的获胜者
- 如果有多位获胜者,输出选举的获胜者们
正确性
check50 cs50/problems/2026/x/plurality
代码风格
style50 plurality.c
如何提交
在终端中执行以下命令提交你的作业,并按提示完成操作。
submit50 cs50/problems/2026/x/plurality