多数制

要解决的问题

选举有各种形式和规模。在英国,首相由君主正式任命,君主通常会选择在下议院赢得最多席位的政党领导人。美国使用多步骤的选举人团流程,公民投票决定每个州如何分配选举人,然后由选举人选举总统。

不过,也许最简单的选举方式是一种通常被称为”多数制投票”的方法(也称为”简单多数制”或”赢者通吃”)。在多数制投票中,每位选民投票给一位候选人。选举结束时,得票最多的候选人被宣布为选举的获胜者。

对于这个问题,你将实现一个程序来运行多数制选举,如下图所示。

演示

分发代码

对于这个问题,你将扩展由 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 有两个字段:一个名为 namestring,表示候选人的姓名;一个名为 votesint,表示该候选人获得的票数。

// 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 函数来输出选举的获胜者(或多位获胜者)。我们留给你来找出实现此功能的代码。

不过,如果你继续往下看文件,你会发现 voteprint_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;
}

这部分就由你来完成了!除了实现 voteprint_winner 函数(以及添加额外的头文件,如果你需要的话)之外,你不应该修改 plurality.c 中的任何其他内容。

提示

点击下方的折叠按钮来阅读一些建议!

完成 vote 函数

接下来,完成 vote 函数。

  • 请注意,vote 的签名 bool vote(string name) 表明它接受一个参数,即一个名为 namestring,表示被投票的候选人的姓名。
  • vote 应返回一个 bool,其中 true 表示投票成功,false 表示投票未成功。

解决此问题的一种方法如下:

  1. 遍历每位候选人
    1. 检查候选人的姓名是否与输入 name 匹配
      1. 如果是,增加该候选人的票数并返回 true
      2. 如果不是,继续检查
  2. 如果检查所有候选人后都没有匹配,返回 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))。

考虑一下,解决此问题你只需要两条信息:

  1. 最高票数
  2. 拥有该票数的候选人(或各位候选人)

因此,一个好的解决方案可能只需要两次搜索。写一些伪代码来提醒自己做这件事:

// 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 MAX of 9)
  • 按姓名投票给候选人
  • 投票给不在选票上的候选人的无效投票
  • 如果只有一位获胜者,输出选举的获胜者
  • 如果有多位获胜者,输出选举的获胜者们

正确性

check50 cs50/problems/2026/x/plurality

代码风格

style50 plurality.c

如何提交

在终端中执行以下命令提交你的作业,并按提示完成操作。

submit50 cs50/problems/2026/x/plurality