Mehrheitswahl
Aufgabe
Wahlen gibt es in allen Formen und Größenordnungen. Im Vereinigten Königreich wird der Premierminister offiziell vom Monarchen ernannt, der in der Regel den Führer der politischen Partei wählt, die die meisten Sitze im Unterhaus gewinnt. In den Vereinigten Staaten gibt es ein mehrstufiges Electoral College, in dem die Bürger darüber abstimmen, wie die einzelnen Bundesstaaten die Wahlmänner verteilen sollen, die dann den Präsidenten wählen.
Die vielleicht einfachste Art, eine Wahl abzuhalten, ist jedoch die sogenannte “Pluralitätswahl” oder Mehrheitswahl (auch bekannt als “first-past-the-post” oder “winner take all”). Bei der Mehrheitswahl kann jeder Wähler für einen Kandidaten stimmen. Der Kandidat, der am Ende der Wahl die meisten Stimmen erhalten hat, wird zum Sieger erklärt.
In dieser Aufgabe werden wir ein Programm implementieren, das eine Mehrheitswahl durchführt. Beachten Sie die Anweisungen in den folgenden Abschnitten.
Demo
Aufgabenmaterial
Für diese Aufgabe werden Sie ein von uns zur Verfügung gestelltes Codegerüst vervollständigen.
Aufgabenmaterial herunterladen
Öffnen Sie VS Code entsprechend Ihrem Setup.
Öffnen Sie Ihr Terminalfenster und führen Sie dann cd
aus. Die Eingabeaufforderung Ihres Terminalfensters sollte wie folgt aussehen:
$
Geben Sie dann
wget https://inf.zone/download/exercises/03/plurality.zip
ein und führen Sie den Befehl mit der Eingabetaste aus, um eine ZIP-Datei namens plurality.zip
in den aktuellen Ordner herunterzuladen. Achten Sie darauf, dass Sie das Leerzeichen zwischen wget
und der folgenden URL nicht übersehen, und auch kein anderes Zeichen!
Führen Sie jetzt
unzip plurality.zip
aus, um das ZIP-Archiv in einen Ordner namens plurality
zu extrahieren. Sie brauchen die ZIP-Datei nicht mehr, also können Sie
rm plurality.zip
ausführen. Antworten Sie mit “y”, gefolgt von der Eingabetaste, um die heruntergeladene ZIP-Datei zu entfernen.
Führen Sie dann
cd plurality
aus, um in dieses Verzeichnis zu wechseln. Ihre Eingabeaufforderung sollte nun wie folgt aussehen:
plurality/ $
Wenn alles funktioniert hat, sollten Sie nach dem Ausführen von
ls
eine Datei mit dem Namen plurality.c
sehen. Wenn Sie code plurality.c
ausführen, sollte sich die Datei öffnen. In diese Datei werden Sie Ihren Code für diese Aufgabe einfügen. Wenn diese Datei nicht angezeigt wird, verfolgen Sie Ihre Schritte zurück und schauen Sie, ob Sie herausfinden können, wo Sie einen Fehler gemacht haben!
Überblick über plurality.c
Wenn Sie die Funktionalität eines bestehenden Codes erweitern wollen, sollten Sie ihn zunächst in seinem jetzigen Zustand verstehen.
Sehen wir uns zuerst den Anfang der Datei an. Die Zeile #define MAX 9
bedeutet, dass MAX
eine Konstante ist (gleich 9
), die im gesamten Programm verwendet werden kann. Hier steht sie für die maximale Anzahl von Kandidaten, die eine Wahl haben kann.
// Max number of candidates
#define MAX 9
Diese Konstante wird in plurality.c
verwendet, um ein globales Array zu definieren - also ein Array, auf das jede Funktion zugreifen kann.
// Array of candidates
candidate candidates[MAX];
Aber was ist in diesem Fall ein candidate
? In plurality.c
ist ein candidate
eine struct
. Jeder candidate
hat zwei Member: einen string
namens name
, der den Namen des Kandidaten enthält, und einen int
namens votes
, in dem die Anzahl der Stimmen gespeichert werden, die der Kandidat hat.
// Candidates have name and vote count
typedef struct
{
string name;
int votes;
}
candidate;
Werfen wir nun einen Blick auf die main
-Funktion. Finden Sie die Stelle, an der das Programm eine globale Variable candidate_count
setzt, die die Anzahl der Kandidaten bei der Wahl angibt?
// Number of candidates
int candidate_count;
Was ist mit der Stelle, an der die Befehlszeilenargumente in das Array candidates
kopiert werden?
// 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;
}
Und wo wird der Benutzer aufgefordert, die Anzahl der Wähler einzugeben?
int voter_count = get_int("Number of voters: ");
Danach lässt das Programm jeden Wähler eine Stimme eingeben und ruft die Funktion vote
für den jeweils gewählten Kandidaten auf. Schließlich ruft main
die Funktion print_winner
auf, um den (oder die) Gewinner der Wahl auszugeben.
Wenn Sie weiter unten in der Datei nachsehen, werden Sie feststellen, dass die Funktionen vote
und print_winner
leer geblieben sind.
// 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;
}
Dieser Teil soll von Ihnen selbst vervollständigt werden!
Zusätzlicher Hinweis: Sie sollten nichts in plurality.c
ändern, außer den Implementierungen der Funktionen vote
und print_winner
. Überdenken Sie stattdessen Ihren Lösungsansatz, falls dieser nur mit einer Änderung an einer anderen Stelle im Code funktioniert.
Hilfestellung
Klicken Sie auf die folgenden Tipps, um einige Ratschläge zu erhalten!
Implementierung der vote
-Funktion
Was gibt es bei der vote
-Funktion zu beachten?
- Die Signatur von
vote
,bool vote(string name)
, zeigt, dass diese genau ein Argument entgegennimmt, einenstring
namensname
, das den Namen des Kandidaten enthält, für den gestimmt wurde. vote
sollte einenbool
zurückgeben, wobeitrue
bedeutet, dass eine Stimme erfolgreich abgegeben wurde (d.h. der übergebene Name stimmt mit dem Namen eines Kandidaten überein) undfalse
, dass dies nicht der Fall war.
Eine Möglichkeit, dieses Problem anzugehen, ist die folgende:
- Iterieren über jeden Kandidaten
- Prüfen, ob der Name des Kandidaten mit der Eingabe
name
übereinstimmt- Wenn ja, Stimmen dieses Kandidaten erhöhen und
true
zurückgegeben - Wenn nein, weiter prüfen
- Wenn ja, Stimmen dieses Kandidaten erhöhen und
- Prüfen, ob der Name des Kandidaten mit der Eingabe
- Gab es keine Übereinstimmung nach der Prüfung aller Kandidaten, wird
false
zurückgegeben
Schreiben Sie diese Schritte als Pseudocode in die Datei und implementieren Sie sie dann der Reihe nach.
// 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
}
Die Implementation in Code überlassen wir allerdings Ihnen!
Implementierung der print_winner
-Funktion
Ein paar Hilfestellungen zur Vervollständigen der print_winner
-Funktion:
- Die Funktion sollte den Namen des Kandidaten ausgeben, der bei der Wahl die meisten Stimmen erhalten hat, gefolgt von einem Zeilenumbruch.
- Die Wahl kann unentschieden ausgehen, wenn mehrere Kandidaten jeweils die Höchstzahl der Stimmen erhalten haben. In diesem Fall sollten Sie die Namen dieser Kandidaten jeweils in einer eigenen Zeile ausgeben.
Vielleicht denken Sie zur Lösung des Problems zuerst an einen Sortieralgorithmus: Die Kandidaten nach ihrer Stimmenzahl sortieren und dann den Spitzenkandidaten (oder die Spitzenkandidaten) ausgeben. Bedenken Sie jedoch, dass das Sortieren komplex sein kann: Selbst Merge Sort, einer der schnellsten Sortieralgorithmen, läuft in $O(N \space log(N))$.
Bedenken Sie, dass Sie zur Lösung dieses Problems im Grunde nur zwei Informationen benötigen:
- Die Höchstzahl der Stimmen unter den Kandidaten.
- Der Kandidat (oder die Kandidaten) mit dieser Anzahl an Stimmen.
Eine gute Lösung würde daher höchstens zwei Suchvorgänge (jeweils $O(N)$) erfordern.
Schreiben wir einen Pseudocode, um die beiden benötigten Suchvorgänge festzuhalten:
// 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
}
Den konkreten Code überlassen wir aber Ihnen!
Testen
Stellen Sie beim Testen Ihres Codes sicher, dass dieser mit folgenden Szenarien umgehen kann:
- einer Wahl mit einer beliebigen Anzahl von Kandidaten (bis zum
MAX
von9
) - der Stimmabgabe für einen Kandidaten nach Namen
- ungültigen Stimmen für Kandidaten, die nicht auf dem Stimmzettel stehen
- der Ausgabe des Gewinners der Wahl, wenn es nur einen gibt
- der Ausgabe der Gewinner der Wahl (jeweils in einer eigenen Zeile), wenn es mehrere gibt
Korrektheit
Führen Sie in Ihrem Terminal den folgenden Befehl aus, um die Korrektheit Ihrer Arbeit zu überprüfen:
check50 -l cs50/problems/2024/x/plurality
Style
Führen Sie den folgenden Befehl aus, um den Stil Ihres Codes mit style50
zu analysieren:
style50 plurality.c