Lerninhalte finden
Features
Entdecke
© StudySmarter 2024, all rights reserved.
Stell Dir vor, Du entwickelst eine Software zum Verwalten von Studenteninformationen an der Universität Erlangen-Nürnberg. Die Software soll grundlegende Informationen eines Studenten enthalten und folgende Abfragen ermöglichen:
Verwende eine Programmiersprache Deiner Wahl, aber achte darauf, die Syntaxregeln und Konzepte zu berücksichtigen, die in den Vorlesungsunterlagen erwähnt wurden.
Subexercise 1: Schreibe eine Funktion eingabeStudent(), die die Informationen eines Studenten von der Konsole einliest. Die Funktion soll einen Datentyp, z.B. ein Dictionary oder eine Struktur, verwenden, um die Studenteninformationen zu speichern. Erläutere den Code und beschreibe, wie die lexikalische Analyse und die Syntaxanalyse in dem von Dir verwendeten Code greifen.
def eingabeStudent(): name = input('Name eingeben: ') matrikelnummer = input('Matrikelnummer eingeben: ') studiengang = input('Studiengang eingeben: ') student = { 'Name': name, 'Matrikelnummer': matrikelnummer, 'Studiengang': studiengang } return student
Lösung:
Um die gestellte Aufgabe zu lösen, erstellen wir eine Funktion namens eingabeStudent(), die die Studenteninformationen von der Konsole einliest und in einem Dictionary speichert. Dies ist eine einfache und effiziente Möglichkeit, die Informationen strukturiert zu speichern.
Hier ist der Code, mit einer detaillierten Erläuterung:
def eingabeStudent(): name = input('Name eingeben: ') matrikelnummer = input('Matrikelnummer eingeben: ') studiengang = input('Studiengang eingeben: ') student = { 'Name': name, 'Matrikelnummer': matrikelnummer, 'Studiengang': studiengang } return student
Erläuterung des Codes:
Lexikalische Analyse und Syntaxanalyse:
Durch die Kombination dieser beiden Analyseschritte wird sichergestellt, dass der Code sowohl lexikalisch korrekt (gültige Token) als auch syntaktisch korrekt (richtige Reihenfolge und Struktur der Token) ist.
Subexercise 2: Implementiere eine weitere Funktion aktualisiereStudiengang(student, neuerStudiengang), die den Studiengang eines existierenden Studentendatensatzes ändert. Verfasse zusätzlich eine Kontrolle, die die gültige Dateneingabe (Typprüfung) der Matrikelnummer sicherstellt. Beschreibe die Funktionalität und erläutere, wie Kontrollstrukturen und Typprüfungen verwendet werden.
def aktualisiereStudiengang(student, neuerStudiengang): if not isinstance(student['Matrikelnummer'], str): raise ValueError('Ungültige Matrikelnummer') student['Studiengang'] = neuerStudiengang return student
Lösung:
Um die gestellte Aufgabe zu lösen, erstellen wir eine Funktion namens aktualisiereStudiengang(student, neuerStudiengang), die den Studiengang eines existierenden Studentendatensatzes ändert. Zusätzlich fügen wir eine Typprüfung hinzu, um sicherzustellen, dass die Matrikelnummer ein gültiger String ist.
Hier ist der vollständige Code, gefolgt von einer detaillierten Erläuterung:
def aktualisiereStudiengang(student, neuerStudiengang): if not isinstance(student['Matrikelnummer'], str): raise ValueError('Ungültige Matrikelnummer') student['Studiengang'] = neuerStudiengang return student
Erläuterung des Codes:
Funktionalität:
Verwendung von Kontrollstrukturen und Typprüfungen:
Du arbeitest an einem Projekt zur Simulation einer Verkehrssignalsteuerung. Du wirst Schleifen und Bedingungen nutzen, um die Signale für Autos und Fußgänger zu steuern. Das Verkehrssignal folgt einem einfachen Ablauf:
Beschreibe die Bedeutung einer do-while-Schleife in einer solchen Simulation und erläutere, warum sie gegenüber einer normalen while-Schleife bevorzugt werden könnte. Implementiere die Simulation erneut unter Verwendung einer do-while-Schleife.
Lösung:
In einer Verkehrssignalsteuerung-Simulation kannst Du eine do-while-Schleife nutzen, um sicherzustellen, dass ein bestimmter Codeblock mindestens einmal ausgeführt wird, bevor eine Bedingung geprüft wird. Das ist besonders sinnvoll, wenn Du sicherstellen möchtest, dass der Ablauf der Ampelsteuerung mindestens einmal vollständig durchläuft.
Vorteile gegenüber einer normalen while-Schleife:
let autosAmpel = 'gruen';let fussgaengerAmpel = 'rot';let zeit = 0;do { if (autosAmpel === 'gruen') { // Ampel für Autos ist grün für 60 Sekunden zeit = 60; fussgaengerAmpel = 'rot'; console.log(`Autos: ${autosAmpel}, Fußgänger: ${fussgaengerAmpel} für ${zeit} Sekunden`); autosAmpel = 'gelb'; } else if (autosAmpel === 'gelb') { // Ampel für Autos ist gelb für 5 Sekunden zeit = 5; console.log(`Autos: ${autosAmpel}, Fußgänger: ${fussgaengerAmpel} für ${zeit} Sekunden`); autosAmpel = 'rot'; } else if (autosAmpel === 'rot') { // Ampel für Autos ist rot, Fußgängerampel wird grün für 30 Sekunden fussgaengerAmpel = 'gruen'; zeit = 30; console.log(`Autos: ${autosAmpel}, Fußgänger: ${fussgaengerAmpel} für ${zeit} Sekunden`); fussgaengerAmpel = 'rot'; autosAmpel = 'gruen'; // Zyklus beginnt von Neuem }} while (true);
Stelle dir vor, das System muss erweitert werden, um eine Priorität für Notfallfahrzeuge zu berücksichtigen. Die Ampel sollte auf grün schalten, wenn ein Notfallfahrzeug erkannt wird. Implementiere eine zusätzliche Bedingung für diese Anforderung in die bestehende Simulation. Verwende eine boolean
-Variable notfall
, die auf true
gesetzt wird, wenn ein Notfallfahrzeug eintrifft.
Lösung:
Um die Simulation so zu erweitern, dass sie eine Priorität für Notfallfahrzeuge berücksichtigt, kannst Du eine zusätzliche Bedingung einfügen. Wenn die Variable notfall
auf true
gesetzt wird, sollte die Ampel für Autos sofort auf grün schalten. Hier ist, wie Du dies in den bestehenden Code integrieren kannst:
let autosAmpel = 'gruen';let fussgaengerAmpel = 'rot';let zeit = 0;let notfall = false;do { if (notfall === true) { // Wenn ein Notfallfahrzeug erkannt wird, wird die Autos-Ampel sofort grün autosAmpel = 'gruen'; fussgaengerAmpel = 'rot'; zeit = 0; console.log(`Notfall! Autos: ${autosAmpel}, Fußgänger: ${fussgaengerAmpel}`); // Hier kannst Du notfall wieder auf false setzen, nachdem die Ampel grün geworden ist notfall = false; } else { if (autosAmpel === 'gruen') { // Ampel für Autos ist grün für 60 Sekunden zeit = 60; fussgaengerAmpel = 'rot'; console.log(`Autos: ${autosAmpel}, Fußgänger: ${fussgaengerAmpel} für ${zeit} Sekunden`); autosAmpel = 'gelb'; } else if (autosAmpel === 'gelb') { // Ampel für Autos ist gelb für 5 Sekunden zeit = 5; console.log(`Autos: ${autosAmpel}, Fußgänger: ${fussgaengerAmpel} für ${zeit} Sekunden`); autosAmpel = 'rot'; } else if (autosAmpel === 'rot') { // Ampel für Autos ist rot, Fußgängerampel wird grün für 30 Sekunden fussgaengerAmpel = 'gruen'; zeit = 30; console.log(`Autos: ${autosAmpel}, Fußgänger: ${fussgaengerAmpel} für ${zeit} Sekunden`); fussgaengerAmpel = 'rot'; autosAmpel = 'gruen'; // Zyklus beginnt von Neuem } }} while (true);
In diesem modifizierten Code wird die Bedingung für Notfälle zuerst überprüft. Wenn ein Notfallfahrzeug erkannt wird (notfall
ist true
), schaltet die Autos-Ampel sofort auf grün und die Fußgängerampel auf rot. Der Wert von notfall
wird dann wieder auf false
gesetzt, damit das System in den normalen Zyklus zurückkehren kann, sobald der Notfall vorbei ist.
Füge eine for-Schleife hinzu, die die Simulation für einen Zeitraum von 24 Stunden durchläuft. Nutze dabei eine Schrittweite von einer Sekunde, um die tatsächliche Zeit zu simulieren (d.h., insgesamt 86400 Iterationen). Berücksichtige dabei die verschiedenen Signalzeiten und die Notfallbedingung.
Lösung:
Um die Simulation für einen Zeitraum von 24 Stunden mit einer Schrittweite von einer Sekunde durchzuführen, können wir eine for-Schleife mit 86400 Iterationen hinzufügen. Dabei berücksichtigen wir die verschiedenen Signalzeiten und die Notfallbedingung. Hier ist die vollständige Implementierung:
let autosAmpel = 'gruen';let fussgaengerAmpel = 'rot';let notfall = false;function signalwechsel(zeit, ampelFarbe, fussgaengerFarbe, notfall) { for (let sekunde = 0; sekunde < zeit; sekunde++) { if (notfall === true) { // Wenn ein Notfallfahrzeug erkannt wird, wird die Autos-Ampel sofort grün autosAmpel = 'gruen'; fussgaengerAmpel = 'rot'; console.log(`Notfall! Autos: ${autosAmpel}, Fußgänger: ${fussgaengerAmpel}`); // notfall wieder auf false setzen, nachdem die Ampel grün geworden ist notfall = false; } else { console.log(`Sekunde ${sekunde}: Autos: ${ampelFarbe}, Fußgänger: ${fussgaengerFarbe}`); } }}for (let i = 0; i < 86400; i++) { if (autosAmpel === 'gruen') { signalwechsel(60, 'gruen', 'rot', notfall); autosAmpel = 'gelb'; } else if (autosAmpel === 'gelb') { signalwechsel(5, 'gelb', 'rot', notfall); autosAmpel = 'rot'; } else if (autosAmpel === 'rot') { signalwechsel(30, 'rot', 'gruen', notfall); autosAmpel = 'gruen'; // Zyklus beginnt von Neuem }}
In dieser Implementierung wird die Funktion signalwechsel
genutzt, um die Signalwechsel und die Notfallbedingung für eine gegebene Zeit zu simulieren. Die Hauptschleife (for
-Schleife) läuft 86400 Iterationen, die jeweils eine Sekunde simulieren und entsprechend den Ampelstatus aktualisieren.
Innerhalb der signalwechsel
-Funktion wird die Notfallbedingung überprüft und entsprechend gehandelt, wenn ein Notfallfahrzeug erkannt wird.
Gegeben sei eine Liste von ganzen Zahlen: L = [34, 7, 23, 32, 5, 62]
. Diese Liste soll mit Hilfe von Sortier- und Suchalgorithmen bearbeitet werden.
Verwende den Merge Sort Algorithmus, um die Liste L
zu sortieren. Zeige alle Zwischenschritte auf, die beim Sortieren der Liste auftreten. Erläutere die Zeitkomplexität und den Speicherbedarf des Merge Sort Algorithmus.
def merge_sort(arr): if len(arr) > 1: mid = len(arr) // 2 L = arr[:mid] R = arr[mid:] merge_sort(L) merge_sort(R) i = j = k = 0 while i < len(L) and j < len(R): if L[i] < R[j]: arr[k] = L[i] i += 1 else: arr[k] = R[j] j += 1 k += 1 while i < len(L): arr[k] = L[i] i += 1 k += 1 while j < len(R): arr[k] = R[j] j += 1 k += 1 return arr
Lösung:
Um die Liste L = [34, 7, 23, 32, 5, 62]
unter Verwendung des Merge Sort Algorithmus zu sortieren, werden wir Schritt für Schritt alle Zwischenschritte aufzeigen. Hier ist der Merge Sort Algorithmus und seine Anwendung auf die gegebene Liste:
def merge_sort(arr): if len(arr) > 1: mid = len(arr) // 2 L = arr[:mid] R = arr[mid:] merge_sort(L) merge_sort(R) i = j = k = 0 while i < len(L) and j < len(R): if L[i] < R[j]: arr[k] = L[i] i += 1 else: arr[k] = R[j] j += 1 k += 1 while i < len(L): arr[k] = L[i] i += 1 k += 1 while j < len(R): arr[k] = R[j] j += 1 k += 1 return arr
Jetzt werden wir die einzelnen Schritte des Merge Sort Algorithmus durchgehen:
[34, 7, 23, 32, 5, 62]
in zwei Hälften: L1 = [34, 7, 23]
und L2 = [32, 5, 62]
.L1
weiter in L11 = [34]
und L12 = [7, 23]
. Teile L2
weiter in L21 = [32]
und L22 = [5, 62]
.L12
in L121 = [7]
und L122 = [23]
. Teile L22
in L221 = [5]
und L222 = [62]
.L121
und L122
zusammen zu [7, 23]
. Führe die Listen L221
und L222
zusammen zu [5, 62]
.[34]
und [7, 23]
zusammen zu [7, 23, 34]
. Führe [32]
und [5, 62]
zusammen zu [5, 32, 62]
.[7, 23, 34]
und [5, 32, 62]
zusammen zu [5, 7, 23, 32, 34, 62]
.Die sortierte Liste lautet somit: [5, 7, 23, 32, 34, 62]
.
Zeitkomplexität: Die Zeitkomplexität des Merge Sort Algorithmus beträgt im schlimmsten Fall O(n log n)
, da die Liste wiederholt in zwei Hälften geteilt wird (was log n
Schritte erfordert) und dann wieder zusammengesetzt wird (was n
Schritte erfordert).
Speicherbedarf: Der Speicherbedarf des Merge Sort Algorithmus ist O(n)
, da zusätzlicher Speicher für die Zwischenlisten während des Teilens und Zusammenfügens der Listen verwendet wird.
Nachdem die Liste L
sortiert wurde, soll die Zahl 32
mit dem Binary Search Algorithmus gesucht werden. Zeige alle Zwischenschritte auf, die beim Suchen gemacht werden. Erläutere die Zeitkomplexität des Binary Search Algorithmus.
def binary_search(arr, x): low = 0 high = len(arr) - 1 mid = 0 while low <= high: mid = (high + low) // 2 if arr[mid] < x: low = mid + 1 elif arr[mid] > x: high = mid - 1 else: return mid return -1
Lösung:
Nachdem die Liste L = [34, 7, 23, 32, 5, 62]
sortiert wurde, haben wir die sortierte Liste sorted_L = [5, 7, 23, 32, 34, 62]
. Jetzt werden wir die Zahl 32
mit dem Binary Search Algorithmus suchen. Der Algorithmus wird wie folgt implementiert und wir zeigen die Zwischenschritte auf:
def binary_search(arr, x): low = 0 high = len(arr) - 1 mid = 0 while low <= high: mid = (high + low) // 2 if arr[mid] < x: low = mid + 1 elif arr[mid] > x: high = mid - 1 else: return mid return -1
Wir wenden den Binary Search Algorithmus auf die sortierte Liste sorted_L = [5, 7, 23, 32, 34, 62]
an, um die Zahl 32
zu finden:
low = 0
, high = 5
(Index der letzten Stelle in der Liste). Berechne mid = (0 + 5) // 2 = 2
. Der Wert an Index 2 ist 23
. Da 23 < 32
, setzen wir low = mid + 1 = 3
.low = 3
, high = 5
. Berechne mid = (3 + 5) // 2 = 4
. Der Wert an Index 4 ist 34
. Da 34 > 32
, setzen wir high = mid - 1 = 3
.low = 3
, high = 3
. Berechne mid = (3 + 3) // 2 = 3
. Der Wert an Index 3 ist 32
. Da 32 == 32
, haben wir die gesuchte Zahl gefunden und der Algorithmus gibt den Index 3
zurück.Die gesuchte Zahl 32
befindet sich an Index 3
in der sortierten Liste.
Zeitkomplexität: Die Zeitkomplexität des Binary Search Algorithmus beträgt O(log n)
, da die Liste in jedem Schritt halbiert wird, was eine logarithmische Anzahl von Schritten in Bezug auf die Größe der Liste erfordert.
Dein Chef hat Dich gebeten, ein Programm zu analysieren, das die Laufzeiten von verschiedenen Sortieralgorithmen vergleicht. Zwei der Algorithmen, die analysiert werden sollen, sind der Bubble-Sort und der Merge-Sort. Beide Sortieralgorithmen sollen auf eine Liste mit n Zahlen angewendet werden. Du musst die Laufzeiten dieser Algorithmen in der Big-O-Notation darstellen. Die Analyse soll sowohl den Average-Case als auch den Worst-Case für beide Algorithmen umfassen, und Du sollst auch eine kurze Begründung für Deine Ergebnisse liefern.
Berechne und notiere die Big-O-Notation für die Average-Case und Worst-Case Laufzeit von Bubble-Sort. Erkläre kurz, warum die jeweilige Laufzeit so berechnet wird.
Lösung:
Um die Big-O-Notation für die Average-Case und Worst-Case Laufzeiten von Bubble-Sort zu berechnen, lass uns zunächst erklären, wie der Bubble-Sort Algorithmus funktioniert.
Schauen wir uns die Laufzeiten im Detail an:
Zusammenfassend:
Die quadratische Laufzeit ergibt sich daraus, dass der Bubble-Sort Algorithmus in beiden Fällen die Liste systematisch durchläuft und dabei jedes Element mit allen anderen Elementen vergleicht und gegebenenfalls vertauscht.
Berechne und notiere die Big-O-Notation für die Average-Case und Worst-Case Laufzeit von Merge-Sort. Erkläre kurz, warum die jeweilige Laufzeit so berechnet wird.
Lösung:
Um die Big-O-Notation für die Average-Case und Worst-Case Laufzeiten von Merge-Sort zu berechnen, lass uns kurz erklären, wie der Merge-Sort Algorithmus funktioniert.
Schauen wir uns die Laufzeiten im Detail an:
Zusammenfassend:
Die logarithmische Laufzeit ergibt sich daraus, dass der Merge-Sort Algorithmus die Liste systematisch in kleinere Teile zerlegt und anschließend effizient kombiniert, was sowohl im Durchschnitt als auch im schlimmsten Fall zu einer optimalen Laufzeit führt.
Mit unserer kostenlosen Lernplattform erhältst du Zugang zu Millionen von Dokumenten, Karteikarten und Unterlagen.
Kostenloses Konto erstellenDu hast bereits ein Konto? Anmelden