diff --git a/linkedAfter/.cs50.yml b/linkedAfter/.cs50.yml new file mode 100644 index 0000000..39c54b8 --- /dev/null +++ b/linkedAfter/.cs50.yml @@ -0,0 +1,10 @@ +submit50: + files: &submit50_files + - !exclude "*" + - !include "*.py" + - !require linkedAfter.py + +check50: + files: *submit50_files + checks: checks/main.py + \ No newline at end of file diff --git a/linkedAfter/checks/__init__.py b/linkedAfter/checks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/linkedAfter/checks/main.py b/linkedAfter/checks/main.py new file mode 100644 index 0000000..296cb8c --- /dev/null +++ b/linkedAfter/checks/main.py @@ -0,0 +1,160 @@ +import check50 +import check50.py + +FILE_NAME = "linkedAfter.py" + + +def to_list(ll): + """LinkedList -> Python-Liste (mit Zyklus-Schutz).""" + out = [] + cur = ll.head + seen = 0 + while cur is not None: + out.append(cur.value) + cur = cur.next + seen += 1 + if seen > 10_000: + msg = f"Linked list appears to have a cycle (more than {seen} nodes)" + raise check50.Failure(msg) + return out + + +def build_ll(module, values): + """Erzeugt eine LinkedList über FromPythonlist (wie in der Aufgabe vorgegeben).""" + ll = module.LinkedList() + ll.FromPythonlist(values) + return ll + + +def a(self, b): + c = self.head + while c is not None: + if c.value == b: + return c + c = c.next + return None + + +@check50.check() +def exists(): + """linkedAfter.py exists""" + check50.exists(FILE_NAME) + + +@check50.check(exists) +def compiles(): + """linkedAfter.py compiles""" + check50.py.compile(FILE_NAME) + + +@check50.check(compiles) +def has_classes_and_method(): + """ListNode, LinkedList and insertAfterNode exist""" + module = check50.py.import_(FILE_NAME) + + if not hasattr(module, "ListNode"): + msg = f"Class `ListNode` not found in {FILE_NAME}" + raise check50.Failure(msg) + + if not hasattr(module, "LinkedList"): + msg = f"Class `LinkedList` not found in {FILE_NAME}" + raise check50.Failure(msg) + + if not hasattr(module.LinkedList(), "insertAfterNode"): + msg = "Method `insertAfterNode` not found in Class `LinkedList`" + raise check50.Failure(msg) + + +@check50.check(has_classes_and_method) +def test_frompythonlist_order_is_head_insertion(): + """FromPythonlist: inserts after head (result is reversed input order)""" + module = check50.py.import_(FILE_NAME) + + ll = build_ll(module, [1, 2, 8, 4]) + expected = [4, 8, 2, 1] # weil insertAfterHead bei Vorwärtsiteration umdreht + actual = to_list(ll) + + if actual != expected: + raise check50.Mismatch(str(expected), str(actual)) + + +@check50.check(has_classes_and_method) +def test_insert_after_middle(): + """insertAfterNode inserts after a middle node (in reversed-built list)""" + module = check50.py.import_(FILE_NAME) + + ll = build_ll(module, [1, 2, 8, 4]) # Liste: 4 -> 8 -> 2 -> 1 + module.LinkedList.searchValue = a + node = ll.searchValue(8) + if node is None: + msg = "searchValue(8) returned None, but 8 should be in the list" + raise check50.Failure(msg) + + ll.insertAfterNode(node, module.ListNode(3)) + + expected = [4, 8, 3, 2, 1] + actual = to_list(ll) + if actual != expected: + raise check50.Mismatch(str(expected), str(actual)) + + +@check50.check(has_classes_and_method) +def test_insert_after_head(): + """insertAfterNode inserts after head""" + module = check50.py.import_(FILE_NAME) + + ll = build_ll(module, [10, 20, 30]) # Liste: 30 -> 20 -> 10 + module.LinkedList.searchValue = a + head = ll.head + if head is None: + msg = "Linked list head is None after FromPythonlist" + raise check50.Failure(msg) + + ll.insertAfterNode(head, module.ListNode(25)) + + expected = [30, 25, 20, 10] + actual = to_list(ll) + if actual != expected: + raise check50.Mismatch(str(expected), str(actual)) + + +@check50.check(has_classes_and_method) +def test_insert_after_tail(): + """insertAfterNode inserts after last node (tail)""" + module = check50.py.import_(FILE_NAME) + + ll = build_ll(module, [10, 20, 30]) # Liste: 30 -> 20 -> 10 + module.LinkedList.searchValue = a + tail = ll.searchValue(10) # 10 ist Tail + if tail is None: + msg = "searchValue(10) returned None, but 10 should be in the list" + raise check50.Failure(msg) + + ll.insertAfterNode(tail, module.ListNode(5)) + + expected = [30, 20, 10, 5] + actual = to_list(ll) + if actual != expected: + raise check50.Mismatch(str(expected), str(actual)) + + +@check50.check(has_classes_and_method) +def test_insert_after_none_prevnode(): + """insertAfterNode with prevNode=None: + We expect an exception (ValueError) rather than silently doing nothing.""" + module = check50.py.import_(FILE_NAME) + + ll = build_ll(module, [1, 2, 3]) + module.LinkedList.searchValue = a + prev = ll.searchValue(999) # not in list -> None + new_node = module.ListNode(4) + + threw = False + try: + ll.insertAfterNode(prev, new_node) + except ValueError: + threw = True + + if not threw: + msg = "insertAfterNode should raise an ValueError when prevNode is None" + raise check50.Failure(msg) diff --git a/linkedAfter/html/linkedAfter.html b/linkedAfter/html/linkedAfter.html new file mode 100644 index 0000000..fb71ea7 --- /dev/null +++ b/linkedAfter/html/linkedAfter.html @@ -0,0 +1,204 @@ +

Linked List: Insert After Node

+ +

+ In dieser Übung werden Sie die Datenstruktur Verkettete Liste (Linked List) erweitern. + Gegeben sind bereits die Klassen ListNode und LinkedList, sowie einige + Hilfsmethoden: FromPythonlist(inputList) zur Erzeugung einer verketteten Liste aus einer Python-Liste + und printList() zur Ausgabe der Liste. Ebenfalls gegeben ist die Methode + searchValue(value), mit deren Hilfe Sie ein Listenelement mit einem bestimmten Wert + suchen können. Ihre Aufgabe ist es, die Methode insertAfterNode(prevNode, newNode) + zu implementieren, die ein neues Listenelement newNode direkt nach dem gegebenen + Element prevNode einfügt. +

+ + +

Aufgabe

+ +

+ Implementieren Sie die Methode insertAfterNode(self, prevNode, newNode) in der Klasse LinkedList. + Die Methode erhält das Element prevNode und das neue Element newNode + und soll das neue Element direkt nach prevNode in die Liste einfügen. Ist prevNode None, + soll eine ValueError-Exception ausgelöst werden. +

+ + +

+ Erstellen Sie eine Datei mit dem Namen + linkedAfter.py und + Implementieren Sie die Methode insertAfterNode in Ihrer Datei. Kopieren Sie dazu den + folgenden Codeblock in die Datei linkedAfter.py, + und ergänzen Sie die Methode insertAfterNode: +

+ +
+

+class ListNode:
+    def __init__(self, value: int):
+        self.value: int = value
+        self.next: ListNode | None = None
+
+
+class LinkedList:
+    def __init__(self):
+        self.head = None
+
+    def FromPythonlist(self, inputList: list[int]):
+        for val in inputList:
+            newNode = ListNode(value=val)
+            self.insertAfterHead(newNode)
+
+    def searchValue(self, value: int) -> ListNode:
+        # Siehe Problem 'linkedFind.py' für die Implementierung dieser Methode
+        return
+
+    def insertAfterNode(self, prevNode: ListNode | None, newNode: ListNode):
+        # TODO: Implementieren Sie diese Methode
+        return
+
+    def printList(self):
+        current = self.head
+        while current is not None:
+            print(current.value, end=" -> ")
+            current = current.next
+        print("None")
+
+    def insertAfterHead(self, newNode: ListNode):
+        newNode.next = self.head
+        self.head = newNode
+
+
+ + + + +

Bevor Sie beginnen

+

Melden Sie sich bei cs50.dev an, klicken Sie + auf Ihr Terminal und führen Sie cd ohne Parameter aus. Sie + sollten feststellen, dass der Prompt Ihres Terminals wie unten aussieht:

+
$
+

Als nächstes führen Sie

+
mkdir + linkedAfter
+

aus, um einen Ordner namens linkedAfter in Ihrem Codespace + zu erstellen.

+

Führen Sie anschließend

+
cd + linkedAfter
+

aus, um in dieses Verzeichnis zu wechseln. Der Prompt Ihres Terminals sollte + nun linkedAfter/$ anzeigen. + Jetzt können Sie

+
code + linkedAfter.py
+

ausführen, um eine Datei namens linkedAfter.py zu erstellen, in der Sie Ihr + Programm schreiben. +

+ +

So testen Sie Ihr Programm

+

So können Sie Ihr Programm manuell testen:

+ +

+ Testen Sie Ihre Implementierung, indem Sie das Skript ausführen. + Erstellen Sie dazu eine Instanz der LinkedList, fügen Sie Elemente hinzu und rufen Sie dann Ihre Methode insertAfterNode auf. + Überprüfen Sie anschließend, ob die Liste die erwartete Struktur hat, indem Sie printList() verwenden. +

+ +
+

+  # Erstellen einer verketteten Liste aus einer Python-Liste
+  inputList = [4, 8, 2, 1]
+  ll = LinkedList()
+  ll.FromPythonlist(inputList)
+
+  print("Liste vorher:")
+  ll.printList()
+
+  node = ll.searchValue(8)
+  newNode = ListNode(3)
+  # Einfügen von 3 nach 8
+  ll.insertAfterNode(node, newNode)
+
+  print("Liste nachher:")
+  ll.printList()
+  # Erwartete Ausgabe: 1 -> 2 -> 8 -> 3 -> 4 -> None
+
+
+ + + +

Sie können das folgende Kommando ausführen, um Ihren Code mit check50 zu überprüfen, einem Programm, das bei + der Abgabe verwendet wird um Ihren Code zu testen. Testen Sie Ihr Programm + aber auch selbst!

+
+ check50 HSDDigitalLabor/problems/adg2025/linkedAfter +
+

+ Grüne Smileys :) + bedeuten, dass Ihr Programm einen Test bestanden hat! Rote + traurige Smileys :( + zeigen an, dass Ihr Programm etwas Unerwartetes ausgegeben + hat. Besuchen Sie die URL, die check50 + ausgibt, um zu sehen, welche Eingabe check50 + an Ihr Programm übergeben hat, welche Ausgabe erwartet wurde und welche + Ausgabe Ihr Programm tatsächlich geliefert hat. +

+ +

Abgabe

+

Führen Sie im Terminal den folgenden Befehl aus, um Ihre Arbeit einzureichen. +

+
+ submit50 HSDDigitalLabor/problems/adg2025/linkedAfter +
+

+ Führen Sie diesen Befehl vor dem Fälligkeitsdatum aus. Sie können Ihre Lösung + nach dem ersten Einsenden noch ändern und erneut einreichen. Bewertet wird + die zuletzt eingereichte Version vor dem Fälligkeitsdatum. Nach Ablauf der + Frist können Sie technisch zwar noch Abgaben tätigen, Ihre Lösung wird jedoch + nicht mehr gewertet. Das Ergebnis kann ausschließlich mit obigem Befehl abgegeben + werden, eine Abgabe in Moodle ist nicht möglich. +

+ +

Markierung der Aufgabe als erledigt

+

Nach dem Einreichen der Lösung mit submit50, + nehmen Sie eine Pseudolösung in Moodle vor, indem Sie auf den Button + + weiter unten auf dieser Seite betätigen und in das sich öffnende Feld unter + "Texteingabe online" den folgenden Text ein: +

+
+ Mit submit50 abgegeben. +
+

Schließen Sie die Eingabe durch Klick auf den Button + unterhalb des Textfeldes ab. +

+

+ Zur besseren Übersicht markieren Sie das Problem linkedAfter.py in Moodle als erledigt, + indem Sie ganz oben auf dieser Seite den Button +

+

+ + klicken. Daraufhin erscheint der Button + +

+ +

generated 2025-12-22 12:27:59

\ No newline at end of file diff --git a/linkedAfter/html/params.json b/linkedAfter/html/params.json new file mode 100644 index 0000000..579ab35 --- /dev/null +++ b/linkedAfter/html/params.json @@ -0,0 +1,9 @@ +{ + "id": "linkedAfter", + "title": "Linked List: Insert After Node", + "foldername": "linkedAfter", + "filename": "linkedAfter.py", + "asciicast_id": "", + "check50_path": "HSDDigitalLabor/problems/adg2025/linkedAfter", + "submit50_path": "HSDDigitalLabor/problems/adg2025/linkedAfter" +} \ No newline at end of file diff --git a/linkedAfter/html/template.html b/linkedAfter/html/template.html new file mode 100644 index 0000000..fe136b9 --- /dev/null +++ b/linkedAfter/html/template.html @@ -0,0 +1,112 @@ +{% include "header.html" %} + +

+ In dieser Übung werden Sie die Datenstruktur Verkettete Liste (Linked List) erweitern. + Gegeben sind bereits die Klassen ListNode und LinkedList, sowie einige + Hilfsmethoden: FromPythonlist(inputList) zur Erzeugung einer verketteten Liste aus einer Python-Liste + und printList() zur Ausgabe der Liste. Ebenfalls gegeben ist die Methode + searchValue(value), mit deren Hilfe Sie ein Listenelement mit einem bestimmten Wert + suchen können. Ihre Aufgabe ist es, die Methode insertAfterNode(prevNode, newNode) + zu implementieren, die ein neues Listenelement newNode direkt nach dem gegebenen + Element prevNode einfügt. +

+ + +

Aufgabe

+ +

+ Implementieren Sie die Methode insertAfterNode(self, prevNode, newNode) in der Klasse LinkedList. + Die Methode erhält das Element prevNode und das neue Element newNode + und soll das neue Element direkt nach prevNode in die Liste einfügen. Ist prevNode None, + soll eine ValueError-Exception ausgelöst werden. +

+ + +

+ {% include "file.html" %} + Implementieren Sie die Methode insertAfterNode in Ihrer Datei. Kopieren Sie dazu den + folgenden Codeblock in die Datei {{filename}}, + und ergänzen Sie die Methode insertAfterNode: +

+ +
+

+class ListNode:
+    def __init__(self, value: int):
+        self.value: int = value
+        self.next: ListNode | None = None
+
+
+class LinkedList:
+    def __init__(self):
+        self.head = None
+
+    def FromPythonlist(self, inputList: list[int]):
+        for val in inputList:
+            newNode = ListNode(value=val)
+            self.insertAfterHead(newNode)
+
+    def searchValue(self, value: int) -> ListNode | None:
+        # Siehe Problem 'linkedFind.py' für die Implementierung dieser Methode
+        return
+
+    def insertAfterNode(self, prevNode: ListNode | None, newNode: ListNode):
+        # TODO: Implementieren Sie diese Methode
+        return
+
+    def printList(self):
+        current = self.head
+        while current is not None:
+            print(current.value, end=" -> ")
+            current = current.next
+        print("None")
+
+    def insertAfterHead(self, newNode: ListNode):
+        newNode.next = self.head
+        self.head = newNode
+
+
+ + + + +{% include "before_you_begin.html" %} + +{% include "how_to_test_head.html" %} + +

+ Testen Sie Ihre Implementierung, indem Sie das Skript ausführen. + Erstellen Sie dazu eine Instanz der LinkedList, fügen Sie Elemente hinzu und rufen Sie dann Ihre Methode insertAfterNode auf. + Überprüfen Sie anschließend, ob die Liste die erwartete Struktur hat, indem Sie printList() verwenden. +

+ +
+

+  # Erstellen einer verketteten Liste aus einer Python-Liste
+  inputList = [4, 8, 2, 1]
+  ll = LinkedList()
+  ll.FromPythonlist(inputList)
+
+  print("Liste vorher:")
+  ll.printList()
+
+  node = ll.searchValue(8)
+  newNode = ListNode(3)
+  # Einfügen von 3 nach 8
+  ll.insertAfterNode(node, newNode)
+
+  print("Liste nachher:")
+  ll.printList()
+  # Erwartete Ausgabe: 1 -> 2 -> 8 -> 3 -> 4 -> None
+
+
+ + + +{% include "how_to_test_auto.html" %} + +{% include "how_to_submit.html" %} + +{% include "how_to_mark_in_moodle.html" %} + +{% include "footer.html" %} \ No newline at end of file diff --git a/linkedFind/.cs50.yml b/linkedFind/.cs50.yml new file mode 100644 index 0000000..82f0073 --- /dev/null +++ b/linkedFind/.cs50.yml @@ -0,0 +1,10 @@ +submit50: + files: &submit50_files + - !exclude "*" + - !include "*.py" + - !require linkedFind.py + +check50: + files: *submit50_files + checks: checks/main.py + \ No newline at end of file diff --git a/linkedFind/checks/__init__.py b/linkedFind/checks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/linkedFind/checks/main.py b/linkedFind/checks/main.py new file mode 100644 index 0000000..a9b77b4 --- /dev/null +++ b/linkedFind/checks/main.py @@ -0,0 +1,132 @@ +import check50 +import check50.py + +FILE_NAME = "linkedFind.py" + + +def build_ll(module, values): + """Erzeugt eine LinkedList über FromPythonlist (wie in der Aufgabe vorgegeben).""" + ll = module.LinkedList() + ll.FromPythonlist(values) + return ll + + +@check50.check() +def exists(): + """linkedFind.py exists""" + check50.exists(FILE_NAME) + + +@check50.check(exists) +def compiles(): + """linkedFind.py compiles""" + check50.py.compile(FILE_NAME) + + +@check50.check(compiles) +def has_classes_and_method(): + """ListNode, LinkedList and searchValue exist""" + module = check50.py.import_(FILE_NAME) + + if not hasattr(module, "ListNode"): + msg = f"Class `ListNode` not found in {FILE_NAME}" + raise check50.Failure(msg) + + if not hasattr(module, "LinkedList"): + msg = f"Class `LinkedList` not found in {FILE_NAME}" + raise check50.Failure(msg) + + if not hasattr(module.LinkedList(), "searchValue"): + msg = "Method `searchValue` not found in Class `LinkedList`" + raise check50.Failure(msg) + + +@check50.check(has_classes_and_method) +def test_search_found_head(): + """searchValue finds the head element""" + module = check50.py.import_(FILE_NAME) + # List: 30 -> 20 -> 10 (FromPythonlist inserts at head) + ll = build_ll(module, [10, 20, 30]) + + found = ll.searchValue(30) + + if found is None: + msg = "searchValue returned None for an existing value (head)" + raise check50.Failure(msg) + + if not isinstance(found, module.ListNode): + msg = "searchValue must return a ListNode object" + raise check50.Failure(msg) + + if found.value != 30: + msg = f"Node with value 30, Node with value {found.value}" + raise check50.Mismatch(msg) + + +@check50.check(has_classes_and_method) +def test_search_found_middle(): + """searchValue finds a middle element""" + module = check50.py.import_(FILE_NAME) + # List: 30 -> 20 -> 10 + ll = build_ll(module, [10, 20, 30]) + + found = ll.searchValue(20) + + if found is None: + msg = "searchValue returned None for an existing value (middle)" + raise check50.Failure(msg) + + if found.value != 20: + msg = "Node with value 20", f"Node with value {found.value}" + raise check50.Mismatch(msg) + + +@check50.check(has_classes_and_method) +def test_search_found_tail(): + """searchValue finds the tail element""" + module = check50.py.import_(FILE_NAME) + # List: 30 -> 20 -> 10 + ll = build_ll(module, [10, 20, 30]) + + found = ll.searchValue(10) + + if found is None: + msg = "searchValue returned None for an existing value (tail)" + raise check50.Failure(msg) + + if found.value != 10: + msg = "Node with value 10", f"Node with value {found.value}" + raise check50.Mismatch(msg) + + +@check50.check(has_classes_and_method) +def test_search_not_found(): + """searchValue returns None for non-existing value""" + module = check50.py.import_(FILE_NAME) + # List: 30 -> 20 -> 10 + ll = build_ll(module, [10, 20, 30]) + + found = ll.searchValue(99) + + if found is not None: + msg = ( + f"searchValue should return None for non-existing value," + f"but returned Node with value {found.value}" + ) + raise check50.Failure(msg) + + +@check50.check(has_classes_and_method) +def test_search_empty_list(): + """searchValue returns None on empty list""" + module = check50.py.import_(FILE_NAME) + ll = module.LinkedList() + + found = ll.searchValue(10) + + if found is not None: + msg = ( + f"searchValue should return None on empty list, " + f"but returned Node with value {found.value}" + ) + raise check50.Failure(msg) diff --git a/linkedFind/html/linkedFind.html b/linkedFind/html/linkedFind.html new file mode 100644 index 0000000..ed877bc --- /dev/null +++ b/linkedFind/html/linkedFind.html @@ -0,0 +1,200 @@ +

Linked List: Ist der Wert in der Liste

+ +

+ In dieser Übung werden Sie die Datenstruktur Verkettete Liste (Linked List) erweitern. + Gegeben sind bereits die Klassen ListNode und LinkedList, sowie einige + Hilfsmethoden: FromPythonlist(inputList) zur Erzeugung einer verketteten Liste aus einer Python-Liste + und printList() zur Ausgabe der Liste. + Ihre Aufgabe ist es, die Methode searchValue(value) + zu implementieren, mit deren Hilfe Sie ein Listenelement mit einem bestimmten Wert + suchen können. +

+ + +

Aufgabe

+ +

+ Implementieren Sie die Methode searchValue(self, value) in der Klasse LinkedList. + Die Methode erhält den Wert value, nach dem gesucht werden soll, und + soll das erste ListNode-Objekt zurückgeben, das diesen Wert enthält. Wird kein Element mit dem + gesuchten Wert gefunden, soll None zurückgegeben werden. +

+ + +

+ Erstellen Sie eine Datei mit dem Namen + linkedFind.py und + Implementieren Sie die Funktion searchValue(self, value) in Ihrer Datei. + Kopieren Sie dazu den folgenden Codeblock in die Datei + linkedFind.py, + und ergänzen Sie die Methode searchValue(self, value): +

+ +
+

+class ListNode:
+    def __init__(self, value: int):
+        self.value: int = value
+        self.next: ListNode | None = None
+
+
+class LinkedList:
+    def __init__(self):
+        self.head = None
+
+    def FromPythonlist(self, inputList: list[int]):
+        for val in inputList:
+            newNode = ListNode(value=val)
+            self.insertAfterHead(newNode)
+
+    def searchValue(self, value: int) -> ListNode | None:
+        # TODO implementieren Sie hier die Suche nach dem Wert
+        return None
+
+    def printList(self):
+        current = self.head
+        while current is not None:
+            print(current.value, end=" -> ")
+            current = current.next
+        print("None")
+
+    def insertAfterHead(self, newNode: ListNode):
+        newNode.next = self.head
+        self.head = newNode
+
+
+ + + + +

Bevor Sie beginnen

+

Melden Sie sich bei cs50.dev an, klicken Sie + auf Ihr Terminal und führen Sie cd ohne Parameter aus. Sie + sollten feststellen, dass der Prompt Ihres Terminals wie unten aussieht:

+
$
+

Als nächstes führen Sie

+
mkdir + linkedFind
+

aus, um einen Ordner namens linkedFind in Ihrem Codespace + zu erstellen.

+

Führen Sie anschließend

+
cd + linkedFind
+

aus, um in dieses Verzeichnis zu wechseln. Der Prompt Ihres Terminals sollte + nun linkedFind/$ anzeigen. + Jetzt können Sie

+
code + linkedFind.py
+

ausführen, um eine Datei namens linkedFind.py zu erstellen, in der Sie Ihr + Programm schreiben. +

+ +

So testen Sie Ihr Programm

+

So können Sie Ihr Programm manuell testen:

+ +

+ Testen Sie Ihre Implementierung, indem Sie das Skript ausführen. + Erstellen Sie dazu eine Instanz der LinkedList, + fügen Sie Elemente hinzu und rufen Sie dann Ihre Methode searchValue auf. + Überprüfen Sie anschließend, ob die Liste die erwartete Struktur hat, + indem Sie printList() verwenden. +

+ +
+

+  # Erstellen einer verketteten Liste aus einer Python-Liste
+  inputList = [1, 2, 8, 4]
+  ll = LinkedList()
+  ll.FromPythonlist(inputList)
+
+  print("Liste:")
+  ll.printList()
+
+  node = ll.searchValue(8)
+  if node is not None:
+      print(f"Gefundenes Element: {node.value}")
+  else:
+      print("Element nicht gefunden.")
+
+
+
+ + + +

Sie können das folgende Kommando ausführen, um Ihren Code mit check50 zu überprüfen, einem Programm, das bei + der Abgabe verwendet wird um Ihren Code zu testen. Testen Sie Ihr Programm + aber auch selbst!

+
+ check50 HSDDigitalLabor/problems/adg2025/linkedFind +
+

+ Grüne Smileys :) + bedeuten, dass Ihr Programm einen Test bestanden hat! Rote + traurige Smileys :( + zeigen an, dass Ihr Programm etwas Unerwartetes ausgegeben + hat. Besuchen Sie die URL, die check50 + ausgibt, um zu sehen, welche Eingabe check50 + an Ihr Programm übergeben hat, welche Ausgabe erwartet wurde und welche + Ausgabe Ihr Programm tatsächlich geliefert hat. +

+ +

Abgabe

+

Führen Sie im Terminal den folgenden Befehl aus, um Ihre Arbeit einzureichen. +

+
+ submit50 HSDDigitalLabor/problems/adg2025/linkedFind +
+

+ Führen Sie diesen Befehl vor dem Fälligkeitsdatum aus. Sie können Ihre Lösung + nach dem ersten Einsenden noch ändern und erneut einreichen. Bewertet wird + die zuletzt eingereichte Version vor dem Fälligkeitsdatum. Nach Ablauf der + Frist können Sie technisch zwar noch Abgaben tätigen, Ihre Lösung wird jedoch + nicht mehr gewertet. Das Ergebnis kann ausschließlich mit obigem Befehl abgegeben + werden, eine Abgabe in Moodle ist nicht möglich. +

+ +

Markierung der Aufgabe als erledigt

+

Nach dem Einreichen der Lösung mit submit50, + nehmen Sie eine Pseudolösung in Moodle vor, indem Sie auf den Button + + weiter unten auf dieser Seite betätigen und in das sich öffnende Feld unter + "Texteingabe online" den folgenden Text ein: +

+
+ Mit submit50 abgegeben. +
+

Schließen Sie die Eingabe durch Klick auf den Button + unterhalb des Textfeldes ab. +

+

+ Zur besseren Übersicht markieren Sie das Problem linkedFind.py in Moodle als erledigt, + indem Sie ganz oben auf dieser Seite den Button +

+

+ + klicken. Daraufhin erscheint der Button + +

+ +

generated 2025-12-22 10:29:53

\ No newline at end of file diff --git a/linkedFind/html/params.json b/linkedFind/html/params.json new file mode 100644 index 0000000..198cb71 --- /dev/null +++ b/linkedFind/html/params.json @@ -0,0 +1,9 @@ +{ + "id": "linkedFind", + "title": "Linked List: Ist der Wert in der Liste", + "foldername": "linkedFind", + "filename": "linkedFind.py", + "asciicast_id": "", + "check50_path": "HSDDigitalLabor/problems/adg2025/linkedFind", + "submit50_path": "HSDDigitalLabor/problems/adg2025/linkedFind" +} \ No newline at end of file diff --git a/linkedFind/html/template.html b/linkedFind/html/template.html new file mode 100644 index 0000000..77d73cb --- /dev/null +++ b/linkedFind/html/template.html @@ -0,0 +1,108 @@ +{% include "header.html" %} + +

+ In dieser Übung werden Sie die Datenstruktur Verkettete Liste (Linked List) erweitern. + Gegeben sind bereits die Klassen ListNode und LinkedList, sowie einige + Hilfsmethoden: FromPythonlist(inputList) zur Erzeugung einer verketteten Liste aus einer Python-Liste + und printList() zur Ausgabe der Liste. + Ihre Aufgabe ist es, die Methode searchValue(value) + zu implementieren, mit deren Hilfe Sie ein Listenelement mit einem bestimmten Wert + suchen können. +

+ + +

Aufgabe

+ +

+ Implementieren Sie die Methode searchValue(self, value) in der Klasse LinkedList. + Die Methode erhält den Wert value, nach dem gesucht werden soll, und + soll das erste ListNode-Objekt zurückgeben, das diesen Wert enthält. Wird kein Element mit dem + gesuchten Wert gefunden, soll None zurückgegeben werden. +

+ + +

+ {% include "file.html" %} + Implementieren Sie die Funktion searchValue(self, value) in Ihrer Datei. + Kopieren Sie dazu den folgenden Codeblock in die Datei + {{filename}}, + und ergänzen Sie die Methode searchValue(self, value): +

+ +
+

+class ListNode:
+    def __init__(self, value: int):
+        self.value: int = value
+        self.next: ListNode | None = None
+
+
+class LinkedList:
+    def __init__(self):
+        self.head = None
+
+    def FromPythonlist(self, inputList: list[int]):
+        for val in inputList:
+            newNode = ListNode(value=val)
+            self.insertAfterHead(newNode)
+
+    def searchValue(self, value: int) -> ListNode | None:
+        # TODO implementieren Sie hier die Suche nach dem Wert
+        return None
+
+    def printList(self):
+        current = self.head
+        while current is not None:
+            print(current.value, end=" -> ")
+            current = current.next
+        print("None")
+
+    def insertAfterHead(self, newNode: ListNode):
+        newNode.next = self.head
+        self.head = newNode
+
+
+ + + + +{% include "before_you_begin.html" %} + +{% include "how_to_test_head.html" %} + +

+ Testen Sie Ihre Implementierung, indem Sie das Skript ausführen. + Erstellen Sie dazu eine Instanz der LinkedList, + fügen Sie Elemente hinzu und rufen Sie dann Ihre Methode searchValue auf. + Überprüfen Sie anschließend, ob die Liste die erwartete Struktur hat, + indem Sie printList() verwenden. +

+ +
+

+  # Erstellen einer verketteten Liste aus einer Python-Liste
+  inputList = [1, 2, 8, 4]
+  ll = LinkedList()
+  ll.FromPythonlist(inputList)
+
+  print("Liste:")
+  ll.printList()
+
+  node = ll.searchValue(8)
+  if node is not None:
+      print(f"Gefundenes Element: {node.value}")
+  else:
+      print("Element nicht gefunden.")
+
+
+
+ + + +{% include "how_to_test_auto.html" %} + +{% include "how_to_submit.html" %} + +{% include "how_to_mark_in_moodle.html" %} + +{% include "footer.html" %} \ No newline at end of file diff --git a/linkedInsert/.cs50.yml b/linkedInsert/.cs50.yml new file mode 100644 index 0000000..4cfe528 --- /dev/null +++ b/linkedInsert/.cs50.yml @@ -0,0 +1,10 @@ +submit50: + files: &submit50_files + - !exclude "*" + - !include "*.py" + - !require linkedInsert.py + +check50: + files: *submit50_files + checks: checks/main.py + \ No newline at end of file diff --git a/linkedInsert/checks/__init__.py b/linkedInsert/checks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/linkedInsert/checks/main.py b/linkedInsert/checks/main.py new file mode 100644 index 0000000..e4e4cc6 --- /dev/null +++ b/linkedInsert/checks/main.py @@ -0,0 +1,106 @@ +import check50 +import check50.py + +FILE_NAME = "linkedInsert.py" + + +def to_list(ll): + """LinkedList -> Python-Liste (mit Zyklus-Schutz).""" + out = [] + cur = ll.head + seen = 0 + while cur is not None: + out.append(cur.value) + cur = cur.next + seen += 1 + if seen > 10_000: + msg = f"Linked list appears to have a cycle (more than {seen} nodes)" + raise check50.Failure(msg) + return out + + +def build_ll(module, values): + """Erzeugt eine LinkedList über FromPythonlist (wie in der Aufgabe vorgegeben).""" + ll = module.LinkedList() + ll.FromPythonlist(values) + return ll + + +@check50.check() +def exists(): + """linkedInsert.py exists""" + check50.exists(FILE_NAME) + + +@check50.check(exists) +def compiles(): + """linkedInsert.py compiles""" + check50.py.compile(FILE_NAME) + + +@check50.check(compiles) +def has_classes_and_method(): + """ListNode, LinkedList and insertAfterLast exist""" + module = check50.py.import_(FILE_NAME) + + if not hasattr(module, "ListNode"): + msg = f"Class `ListNode` not found in {FILE_NAME}" + raise check50.Failure(msg) + + if not hasattr(module, "LinkedList"): + msg = f"Class `LinkedList` not found in {FILE_NAME}" + raise check50.Failure(msg) + + if not hasattr(module.LinkedList(), "insertAfterLast"): + msg = "Method `insertAfterLast` not found in Class `LinkedList`" + raise check50.Failure(msg) + + +@check50.check(has_classes_and_method) +def test_insert_empty_list(): + """insertAfterLast inserts into empty list (becomes head)""" + module = check50.py.import_(FILE_NAME) + ll = module.LinkedList() + + new_node = module.ListNode(10) + ll.insertAfterLast(new_node) + + expected = [10] + actual = to_list(ll) + + if actual != expected: + raise check50.Mismatch(str(expected), str(actual)) + + +@check50.check(has_classes_and_method) +def test_insert_non_empty_list(): + """insertAfterLast appends to non-empty list""" + module = check50.py.import_(FILE_NAME) + # List: 30 -> 20 -> 10 + ll = build_ll(module, [10, 20, 30]) + + new_node = module.ListNode(5) + ll.insertAfterLast(new_node) + + expected = [30, 20, 10, 5] + actual = to_list(ll) + + if actual != expected: + raise check50.Mismatch(str(expected), str(actual)) + + +@check50.check(has_classes_and_method) +def test_insert_multiple(): + """insertAfterLast appends multiple elements correctly""" + module = check50.py.import_(FILE_NAME) + ll = module.LinkedList() + + ll.insertAfterLast(module.ListNode(1)) + ll.insertAfterLast(module.ListNode(2)) + ll.insertAfterLast(module.ListNode(3)) + + expected = [1, 2, 3] + actual = to_list(ll) + + if actual != expected: + raise check50.Mismatch(str(expected), str(actual)) diff --git a/linkedInsert/html/linkedInsert.html b/linkedInsert/html/linkedInsert.html new file mode 100644 index 0000000..b5b4110 --- /dev/null +++ b/linkedInsert/html/linkedInsert.html @@ -0,0 +1,204 @@ +

Linked List: Insert After Last Node

+ +

+ In dieser Übung werden Sie die Datenstruktur Verkettete Liste (Linked List) erweitern. + Gegeben sind bereits die Klassen ListNode und LinkedList, sowie einige + Hilfsmethoden: FromPythonlist(inputList) zur Erzeugung einer verketteten Liste aus einer Python-Liste + und printList() zur Ausgabe der Liste. + Ihre Aufgabe ist es, die Methode insertAfterLast(newNode) + zu implementieren, die ein neues Listenelement newNode an das Ende der Liste einfügt. +

+ + +

Aufgabe

+ +

+ Implementieren Sie die Methode insertAfterLast(self, newNode) in der Klasse LinkedList. + Die Methode erhält das neue Element newNode und soll dieses am Ende der Liste einfügen. + Wenn die Liste leer ist, wird das neue Element zum Kopf (Head) der Liste. +

+ + +

+ Erstellen Sie eine Datei mit dem Namen + linkedInsert.py und + Implementieren Sie die Methode insertAfterLast in Ihrer Datei. Kopieren Sie dazu den + folgenden Codeblock in die Datei linkedInsert.py, + und ergänzen Sie die Methode insertAfterLast: +

+ +
+

+class ListNode:
+    def __init__(self, value: int):
+        self.value: int = value
+        self.next: ListNode | None = None
+
+
+class LinkedList:
+    def __init__(self):
+        self.head = None
+
+    def FromPythonlist(self, inputList: list[int]):
+        for val in inputList:
+            newNode = ListNode(value=val)
+            self.insertAfterHead(newNode)
+
+    def searchValue(self, value: int) -> ListNode | None:
+        # Siehe Problem 'linkedFind.py' für die Implementierung dieser Methode
+        return None
+
+    def insertAfterNode(self, prevNode: ListNode | None, newNode: ListNode):
+        # Siehe Problem 'linkedAfter.py' für die Implementierung dieser Methode
+        return
+
+    def insertAfterLast(self, newNode: ListNode):
+        # TODO: Implementieren Sie diese Methode
+        pass
+
+    def printList(self):
+        current = self.head
+        while current is not None:
+            print(current.value, end=" -> ")
+            current = current.next
+        print("None")
+
+    def insertAfterHead(self, newNode: ListNode):
+        newNode.next = self.head
+        self.head = newNode
+
+
+ + + + +

Bevor Sie beginnen

+

Melden Sie sich bei cs50.dev an, klicken Sie + auf Ihr Terminal und führen Sie cd ohne Parameter aus. Sie + sollten feststellen, dass der Prompt Ihres Terminals wie unten aussieht:

+
$
+

Als nächstes führen Sie

+
mkdir + linkedInsert
+

aus, um einen Ordner namens linkedInsert in Ihrem Codespace + zu erstellen.

+

Führen Sie anschließend

+
cd + linkedInsert
+

aus, um in dieses Verzeichnis zu wechseln. Der Prompt Ihres Terminals sollte + nun linkedInsert/$ anzeigen. + Jetzt können Sie

+
code + linkedInsert.py
+

ausführen, um eine Datei namens linkedInsert.py zu erstellen, in der Sie Ihr + Programm schreiben. +

+ +

So testen Sie Ihr Programm

+

So können Sie Ihr Programm manuell testen:

+ +

+ Testen Sie Ihre Implementierung, indem Sie das Skript ausführen. + Erstellen Sie dazu eine Instanz der LinkedList, fügen Sie Elemente hinzu und rufen Sie dann Ihre Methode insertAfterLast auf. + Überprüfen Sie anschließend, ob die Liste die erwartete Struktur hat, indem Sie printList() verwenden. +

+ +
+

+  # Erstellen einer verketteten Liste aus einer Python-Liste
+  inputList = [4, 8, 2, 1]
+  ll = LinkedList()
+  ll.FromPythonlist(inputList)
+
+  print("Liste vorher:")
+  ll.printList()
+
+  newNode = ListNode(99)
+  # Einfügen von 99 am Ende
+  ll.insertAfterLast(newNode)
+
+  print("Liste nachher:")
+  ll.printList()
+  # Erwartete Ausgabe: 1 -> 2 -> 8 -> 4 -> 99 -> None
+
+
+ + + +

Sie können das folgende Kommando ausführen, um Ihren Code mit check50 zu überprüfen, einem Programm, das bei + der Abgabe verwendet wird um Ihren Code zu testen. Testen Sie Ihr Programm + aber auch selbst!

+
+ check50 HSDDigitalLabor/problems/adg2025/linkedInsert +
+

+ Grüne Smileys :) + bedeuten, dass Ihr Programm einen Test bestanden hat! Rote + traurige Smileys :( + zeigen an, dass Ihr Programm etwas Unerwartetes ausgegeben + hat. Besuchen Sie die URL, die check50 + ausgibt, um zu sehen, welche Eingabe check50 + an Ihr Programm übergeben hat, welche Ausgabe erwartet wurde und welche + Ausgabe Ihr Programm tatsächlich geliefert hat. +

+ +

Abgabe

+

Führen Sie im Terminal den folgenden Befehl aus, um Ihre Arbeit einzureichen. +

+
+ submit50 HSDDigitalLabor/problems/adg2025/linkedInsert +
+

+ Führen Sie diesen Befehl vor dem Fälligkeitsdatum aus. Sie können Ihre Lösung + nach dem ersten Einsenden noch ändern und erneut einreichen. Bewertet wird + die zuletzt eingereichte Version vor dem Fälligkeitsdatum. Nach Ablauf der + Frist können Sie technisch zwar noch Abgaben tätigen, Ihre Lösung wird jedoch + nicht mehr gewertet. Das Ergebnis kann ausschließlich mit obigem Befehl abgegeben + werden, eine Abgabe in Moodle ist nicht möglich. +

+ +

Markierung der Aufgabe als erledigt

+

Nach dem Einreichen der Lösung mit submit50, + nehmen Sie eine Pseudolösung in Moodle vor, indem Sie auf den Button + + weiter unten auf dieser Seite betätigen und in das sich öffnende Feld unter + "Texteingabe online" den folgenden Text ein: +

+
+ Mit submit50 abgegeben. +
+

Schließen Sie die Eingabe durch Klick auf den Button + unterhalb des Textfeldes ab. +

+

+ Zur besseren Übersicht markieren Sie das Problem linkedInsert.py in Moodle als erledigt, + indem Sie ganz oben auf dieser Seite den Button +

+

+ + klicken. Daraufhin erscheint der Button + +

+ +

generated 2025-12-22 10:30:01

\ No newline at end of file diff --git a/linkedInsert/html/params.json b/linkedInsert/html/params.json new file mode 100644 index 0000000..8feb51e --- /dev/null +++ b/linkedInsert/html/params.json @@ -0,0 +1,9 @@ +{ + "id": "linkedInsert", + "title": "Linked List: Insert After Last Node", + "foldername": "linkedInsert", + "filename": "linkedInsert.py", + "asciicast_id": "", + "check50_path": "HSDDigitalLabor/problems/adg2025/linkedInsert", + "submit50_path": "HSDDigitalLabor/problems/adg2025/linkedInsert" +} \ No newline at end of file diff --git a/linkedInsert/html/template.html b/linkedInsert/html/template.html new file mode 100644 index 0000000..9005e14 --- /dev/null +++ b/linkedInsert/html/template.html @@ -0,0 +1,112 @@ +{% include "header.html" %} + +

+ In dieser Übung werden Sie die Datenstruktur Verkettete Liste (Linked List) erweitern. + Gegeben sind bereits die Klassen ListNode und LinkedList, sowie einige + Hilfsmethoden: FromPythonlist(inputList) zur Erzeugung einer verketteten Liste aus einer Python-Liste + und printList() zur Ausgabe der Liste. + Ihre Aufgabe ist es, die Methode insertAfterLast(newNode) + zu implementieren, die ein neues Listenelement newNode an das Ende der Liste einfügt. +

+ + +

Aufgabe

+ +

+ Implementieren Sie die Methode insertAfterLast(self, newNode) in der Klasse LinkedList. + Die Methode erhält das neue Element newNode und soll dieses am Ende der Liste einfügen. + Wenn die Liste leer ist, wird das neue Element zum Kopf (Head) der Liste. +

+ + +

+ {% include "file.html" %} + Implementieren Sie die Methode insertAfterLast in Ihrer Datei. Kopieren Sie dazu den + folgenden Codeblock in die Datei {{filename}}, + und ergänzen Sie die Methode insertAfterLast: +

+ +
+

+class ListNode:
+    def __init__(self, value: int):
+        self.value: int = value
+        self.next: ListNode | None = None
+
+
+class LinkedList:
+    def __init__(self):
+        self.head = None
+
+    def FromPythonlist(self, inputList: list[int]):
+        for val in inputList:
+            newNode = ListNode(value=val)
+            self.insertAfterHead(newNode)
+
+    def searchValue(self, value: int) -> ListNode | None:
+        # Siehe Problem 'linkedFind.py' für die Implementierung dieser Methode
+        return None
+
+    def insertAfterNode(self, prevNode: ListNode | None, newNode: ListNode):
+        # Siehe Problem 'linkedAfter.py' für die Implementierung dieser Methode
+        return
+
+    def insertAfterLast(self, newNode: ListNode):
+        # TODO: Implementieren Sie diese Methode
+        pass
+
+    def printList(self):
+        current = self.head
+        while current is not None:
+            print(current.value, end=" -> ")
+            current = current.next
+        print("None")
+
+    def insertAfterHead(self, newNode: ListNode):
+        newNode.next = self.head
+        self.head = newNode
+
+
+ + + + +{% include "before_you_begin.html" %} + +{% include "how_to_test_head.html" %} + +

+ Testen Sie Ihre Implementierung, indem Sie das Skript ausführen. + Erstellen Sie dazu eine Instanz der LinkedList, fügen Sie Elemente hinzu und rufen Sie dann Ihre Methode insertAfterLast auf. + Überprüfen Sie anschließend, ob die Liste die erwartete Struktur hat, indem Sie printList() verwenden. +

+ +
+

+  # Erstellen einer verketteten Liste aus einer Python-Liste
+  inputList = [4, 8, 2, 1]
+  ll = LinkedList()
+  ll.FromPythonlist(inputList)
+
+  print("Liste vorher:")
+  ll.printList()
+
+  newNode = ListNode(99)
+  # Einfügen von 99 am Ende
+  ll.insertAfterLast(newNode)
+
+  print("Liste nachher:")
+  ll.printList()
+  # Erwartete Ausgabe: 1 -> 2 -> 8 -> 4 -> 99 -> None
+
+
+ + + +{% include "how_to_test_auto.html" %} + +{% include "how_to_submit.html" %} + +{% include "how_to_mark_in_moodle.html" %} + +{% include "footer.html" %} \ No newline at end of file diff --git a/linkedMerge/.cs50.yml b/linkedMerge/.cs50.yml new file mode 100644 index 0000000..6f1c3c2 --- /dev/null +++ b/linkedMerge/.cs50.yml @@ -0,0 +1,10 @@ +submit50: + files: &submit50_files + - !exclude "*" + - !include "*.py" + - !require linkedMerge.py + +check50: + files: *submit50_files + checks: checks/main.py + \ No newline at end of file diff --git a/linkedMerge/checks/__init__.py b/linkedMerge/checks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/linkedMerge/checks/main.py b/linkedMerge/checks/main.py new file mode 100644 index 0000000..18eab30 --- /dev/null +++ b/linkedMerge/checks/main.py @@ -0,0 +1,132 @@ +import check50 +import check50.py + +FILE_NAME = "linkedMerge.py" + + +def to_list(ll): + """LinkedList -> Python-Liste (mit Zyklus-Schutz).""" + out = [] + if ll is None or ll.head is None: + return out + + cur = ll.head + seen = 0 + while cur is not None: + out.append(cur.value) + cur = cur.next + seen += 1 + if seen > 10_000: + msg = f"Linked list appears to have a cycle (more than {seen} nodes)" + raise check50.Failure(msg) + return out + + +def build_ll(module, values): + """Erzeugt eine LinkedList über FromPythonlist (wie in der Aufgabe vorgegeben).""" + ll = module.LinkedList() + ll.FromPythonlist(values) + return ll + + +@check50.check() +def exists(): + """linkedMerge.py exists""" + check50.exists(FILE_NAME) + + +@check50.check(exists) +def compiles(): + """linkedMerge.py compiles""" + check50.py.compile(FILE_NAME) + + +@check50.check(compiles) +def has_classes_and_function(): + """ListNode, LinkedList and mergeTwoLists exist""" + module = check50.py.import_(FILE_NAME) + + if not hasattr(module, "ListNode"): + msg = f"Class `ListNode` not found in {FILE_NAME}" + raise check50.Failure(msg) + + if not hasattr(module, "LinkedList"): + msg = f"Class `LinkedList` not found in {FILE_NAME}" + raise check50.Failure(msg) + + if not hasattr(module, "mergeTwoLists"): + msg = f"Function `mergeTwoLists` not found in {FILE_NAME}" + raise check50.Failure(msg) + + +@check50.check(has_classes_and_function) +def test_merge_two_sorted_lists(): + """mergeTwoLists merges two sorted lists correctly""" + module = check50.py.import_(FILE_NAME) + + # List 1: 1 -> 2 -> 4 (Input [4, 2, 1] because FromPythonlist reverses) + ll1 = build_ll(module, [4, 2, 1]) + # List 2: 1 -> 3 -> 4 (Input [4, 3, 1]) + ll2 = build_ll(module, [4, 3, 1]) + + merged = module.mergeTwoLists(ll1, ll2) + + expected = [1, 1, 2, 3, 4, 4] + actual = to_list(merged) + + if actual != expected: + raise check50.Mismatch(str(expected), str(actual)) + + +@check50.check(has_classes_and_function) +def test_merge_empty_lists(): + """mergeTwoLists handles two empty lists""" + module = check50.py.import_(FILE_NAME) + + ll1 = module.LinkedList() + ll2 = module.LinkedList() + + merged = module.mergeTwoLists(ll1, ll2) + + expected = [] + actual = to_list(merged) + + if actual != expected: + raise check50.Mismatch(str(expected), str(actual)) + + +@check50.check(has_classes_and_function) +def test_merge_one_empty_list(): + """mergeTwoLists handles one empty list""" + module = check50.py.import_(FILE_NAME) + + ll1 = module.LinkedList() + # List 2: 0 (Input [0]) + ll2 = build_ll(module, [0]) + + merged = module.mergeTwoLists(ll1, ll2) + + expected = [0] + actual = to_list(merged) + + if actual != expected: + raise check50.Mismatch(str(expected), str(actual)) + + +@check50.check(has_classes_and_function) +def test_merge_different_lengths(): + """mergeTwoLists merges lists of different lengths""" + module = check50.py.import_(FILE_NAME) + + # List 1: 2 (Input [2]) + ll1 = build_ll(module, [2]) + # List 2: 1 -> 3 (Input [3, 1]) + ll2 = build_ll(module, [3, 1]) + + merged = module.mergeTwoLists(ll1, ll2) + + expected = [1, 2, 3] + actual = to_list(merged) + + if actual != expected: + raise check50.Mismatch(str(expected), str(actual)) diff --git a/linkedMerge/html/generate_png.py b/linkedMerge/html/generate_png.py new file mode 100644 index 0000000..feecee9 --- /dev/null +++ b/linkedMerge/html/generate_png.py @@ -0,0 +1,81 @@ +import matplotlib.pyplot as plt +from matplotlib.patches import Circle, FancyArrowPatch +import numpy as np +import os + + +def draw_node(ax, x, y, text, facecolor=None, radius=0.35): + c = Circle( + (x, y), + radius=radius, + linewidth=2, + edgecolor="black", + facecolor=facecolor if facecolor is not None else "white", + ) + ax.add_patch(c) + ax.text(x, y, str(text), ha="center", va="center", fontsize=14, weight="bold") + return c + + +def draw_arrow(ax, x1, y1, x2, y2, radius=0.35): + # Shorten arrow so it touches the circle boundaries + v = np.array([x2 - x1, y2 - y1], dtype=float) + d = np.linalg.norm(v) + if d == 0: + return + u = v / d + start = np.array([x1, y1]) + u * radius + end = np.array([x2, y2]) - u * radius + arrow = FancyArrowPatch( + start, end, arrowstyle="-|>", mutation_scale=15, linewidth=2, color="black" + ) + ax.add_patch(arrow) + + +# Colors (chosen to match the example) +RED = "#e53935" +PURPLE = "#7e57c2" + +fig, ax = plt.subplots(figsize=(10, 4)) + +# --- Top list: 1 -> 2 -> 4 (red) --- +top_y = 2.3 +top_xs = [1.5, 3.5, 5.5] +top_vals = [1, 2, 4] +for x, v in zip(top_xs, top_vals): + draw_node(ax, x, top_y, v, facecolor=RED) +for x1, x2 in zip(top_xs[:-1], top_xs[1:]): + draw_arrow(ax, x1, top_y, x2, top_y) + +# --- Middle list: 1 -> 3 -> 4 (purple) --- +mid_y = 1.2 +mid_xs = [1.5, 3.5, 5.5] +mid_vals = [1, 3, 4] +for x, v in zip(mid_xs, mid_vals): + draw_node(ax, x, mid_y, v, facecolor=PURPLE) +for x1, x2 in zip(mid_xs[:-1], mid_xs[1:]): + draw_arrow(ax, x1, mid_y, x2, mid_y) + +# Separator line +ax.plot([0.5, 6.5], [0.55, 0.55], linewidth=2, color="black") + +# --- Bottom merged list: 1(p) -> 1(r) -> 2(r) -> 3(p) -> 4(r) -> 4(p) --- +bot_y = -0.2 +bot_xs = [0.8, 1.9, 3.0, 4.1, 5.2, 6.3] +bot_vals = [1, 1, 2, 3, 4, 4] +bot_colors = [PURPLE, RED, RED, PURPLE, RED, PURPLE] +for x, v, col in zip(bot_xs, bot_vals, bot_colors): + draw_node(ax, x, bot_y, v, facecolor=col) +for x1, x2 in zip(bot_xs[:-1], bot_xs[1:]): + draw_arrow(ax, x1, bot_y, x2, bot_y) + +# Layout +ax.set_aspect("equal") +ax.set_xlim(0, 7.1) +ax.set_ylim(-1.0, 3.0) +ax.axis("off") + +script_dir = os.path.dirname(os.path.abspath(__file__)) +plt.savefig( + os.path.join(script_dir, "linked_list_graphic.png"), dpi=200, bbox_inches="tight" +) diff --git a/linkedMerge/html/linkedMerge.html b/linkedMerge/html/linkedMerge.html new file mode 100644 index 0000000..f5fd59a --- /dev/null +++ b/linkedMerge/html/linkedMerge.html @@ -0,0 +1,221 @@ +

Linked List: Füge zwei sortierte verkettete Listen zusammen

+ +

+ In dieser Übung werden Sie die Datenstruktur Verkettete Liste (Linked List) erweitern. + Gegeben sind bereits die Klassen ListNode und LinkedList, sowie einige + Hilfsmethoden: FromPythonlist(inputList) zur Erzeugung einer verketteten Liste aus einer Python-Liste + und printList() zur Ausgabe der Liste. + Ihre Aufgabe ist es, die Funktion mergeTwoLists(list1, list2) + zu implementieren, die zwei sortierte verkettete Listen (Objekte vom Typ LinkedList) zu einer einzigen sortierten Liste zusammenfügt. +

+ +

merge +

+ +

Aufgabe

+ +

+ Implementieren Sie die Funktion mergeTwoLists(list1, list2) außerhalb der Klasse LinkedList. + Die Funktion erhält zwei sortierte LinkedList-Objekte, list1 und list2. + Sie soll die beiden Listen so verknüpfen, dass eine einzige, aufsteigend sortierte Liste entsteht. + Geben Sie ein neues LinkedList-Objekt zurück, das die gemergte Liste enthält. +

+ + +

+ Erstellen Sie eine Datei mit dem Namen + linkedMerge.py und + Implementieren Sie die Funktion mergeTwoLists in Ihrer Datei. Kopieren Sie dazu den + folgenden Codeblock in die Datei linkedMerge.py, + und ergänzen Sie die Funktion mergeTwoLists: +

+ +
+

+class ListNode:
+    def __init__(self, value: int):
+        self.value: int = value
+        self.next: ListNode | None = None
+
+
+class LinkedList:
+    def __init__(self):
+        self.head = None
+
+    def FromPythonlist(self, inputList: list[int]):
+        for val in inputList:
+            newNode = ListNode(value=val)
+            self.insertAfterHead(newNode)
+
+    def printList(self):
+        current = self.head
+        while current is not None:
+            print(current.value, end=" -> ")
+            current = current.next
+        print("None")
+
+    def searchValue(self, value: int) -> ListNode | None:
+        # Siehe Problem 'linkedFind.py' für die Implementierung dieser Methode
+        return None
+
+    def insertAfterNode(self, prevNode: ListNode | None, newNode: ListNode):
+        # Siehe Problem 'linkedAfter.py' für die Implementierung dieser Methode
+        return
+
+    def insertAfterLast(self, newNode: ListNode):
+        # Siehe Problem 'linkedInsert.py' für die Implementierung dieser Methode
+        return
+
+    def insertAfterHead(self, newNode: ListNode):
+        newNode.next = self.head
+        self.head = newNode
+
+def mergeTwoLists(list1: LinkedList, list2: LinkedList) -> LinkedList:
+    mergedList = LinkedList()
+    # TODO: Implementieren Sie diese Funktion
+    return mergedList
+
+
+ + + + +

Bevor Sie beginnen

+

Melden Sie sich bei cs50.dev an, klicken Sie + auf Ihr Terminal und führen Sie cd ohne Parameter aus. Sie + sollten feststellen, dass der Prompt Ihres Terminals wie unten aussieht:

+
$
+

Als nächstes führen Sie

+
mkdir + linkedMerge
+

aus, um einen Ordner namens linkedMerge in Ihrem Codespace + zu erstellen.

+

Führen Sie anschließend

+
cd + linkedMerge
+

aus, um in dieses Verzeichnis zu wechseln. Der Prompt Ihres Terminals sollte + nun linkedMerge/$ anzeigen. + Jetzt können Sie

+
code + linkedMerge.py
+

ausführen, um eine Datei namens linkedMerge.py zu erstellen, in der Sie Ihr + Programm schreiben. +

+ +

So testen Sie Ihr Programm

+

So können Sie Ihr Programm manuell testen:

+ +

+ Testen Sie Ihre Implementierung, indem Sie das Skript ausführen. + Erstellen Sie dazu eine Instanz der LinkedList, fügen Sie Elemente hinzu und rufen Sie dann Ihre Funktion mergeTwoLists auf. + Überprüfen Sie anschließend, ob die Liste die erwartete Struktur hat. +

+ +
+

+  # Erstellen zweier sortierter Listen
+  # Hinweis: FromPythonlist fügt vorne ein, daher umgekehrte Reihenfolge für korrekte Sortierung
+  
+  # Liste 1: 1 -> 2 -> 4
+  ll1 = LinkedList()
+  ll1.FromPythonlist([4, 2, 1])
+  
+  # Liste 2: 1 -> 3 -> 4
+  ll2 = LinkedList()
+  ll2.FromPythonlist([4, 3, 1])
+
+  print("Liste 1:")
+  ll1.printList()
+  print("Liste 2:")
+  ll2.printList()
+
+  # Mergen der Listen
+  merged_list = mergeTwoLists(ll1, ll2)
+
+  print("Gemergte Liste:")
+  merged_list.printList()
+  # Erwartete Ausgabe: 1 -> 1 -> 2 -> 3 -> 4 -> 4 -> None
+
+
+ + + +

Sie können das folgende Kommando ausführen, um Ihren Code mit check50 zu überprüfen, einem Programm, das bei + der Abgabe verwendet wird um Ihren Code zu testen. Testen Sie Ihr Programm + aber auch selbst!

+
+ check50 HSDDigitalLabor/problems/adg2025/linkedMerge +
+

+ Grüne Smileys :) + bedeuten, dass Ihr Programm einen Test bestanden hat! Rote + traurige Smileys :( + zeigen an, dass Ihr Programm etwas Unerwartetes ausgegeben + hat. Besuchen Sie die URL, die check50 + ausgibt, um zu sehen, welche Eingabe check50 + an Ihr Programm übergeben hat, welche Ausgabe erwartet wurde und welche + Ausgabe Ihr Programm tatsächlich geliefert hat. +

+ +

Abgabe

+

Führen Sie im Terminal den folgenden Befehl aus, um Ihre Arbeit einzureichen. +

+
+ submit50 HSDDigitalLabor/problems/adg2025/linkedMerge +
+

+ Führen Sie diesen Befehl vor dem Fälligkeitsdatum aus. Sie können Ihre Lösung + nach dem ersten Einsenden noch ändern und erneut einreichen. Bewertet wird + die zuletzt eingereichte Version vor dem Fälligkeitsdatum. Nach Ablauf der + Frist können Sie technisch zwar noch Abgaben tätigen, Ihre Lösung wird jedoch + nicht mehr gewertet. Das Ergebnis kann ausschließlich mit obigem Befehl abgegeben + werden, eine Abgabe in Moodle ist nicht möglich. +

+ +

Markierung der Aufgabe als erledigt

+

Nach dem Einreichen der Lösung mit submit50, + nehmen Sie eine Pseudolösung in Moodle vor, indem Sie auf den Button + + weiter unten auf dieser Seite betätigen und in das sich öffnende Feld unter + "Texteingabe online" den folgenden Text ein: +

+
+ Mit submit50 abgegeben. +
+

Schließen Sie die Eingabe durch Klick auf den Button + unterhalb des Textfeldes ab. +

+

+ Zur besseren Übersicht markieren Sie das Problem linkedMerge.py in Moodle als erledigt, + indem Sie ganz oben auf dieser Seite den Button +

+

+ + klicken. Daraufhin erscheint der Button + +

+ +

generated 2025-12-22 11:31:27

\ No newline at end of file diff --git a/linkedMerge/html/linked_list_graphic.png b/linkedMerge/html/linked_list_graphic.png new file mode 100644 index 0000000..ac8e5e8 Binary files /dev/null and b/linkedMerge/html/linked_list_graphic.png differ diff --git a/linkedMerge/html/params.json b/linkedMerge/html/params.json new file mode 100644 index 0000000..6630cee --- /dev/null +++ b/linkedMerge/html/params.json @@ -0,0 +1,9 @@ +{ + "id": "linkedMerge", + "title": "Linked List: Füge zwei sortierte verkettete Listen zusammen", + "foldername": "linkedMerge", + "filename": "linkedMerge.py", + "asciicast_id": "", + "check50_path": "HSDDigitalLabor/problems/adg2025/linkedMerge", + "submit50_path": "HSDDigitalLabor/problems/adg2025/linkedMerge" +} \ No newline at end of file diff --git a/linkedMerge/html/template.html b/linkedMerge/html/template.html new file mode 100644 index 0000000..0659acb --- /dev/null +++ b/linkedMerge/html/template.html @@ -0,0 +1,129 @@ +{% include "header.html" %} + +

+ In dieser Übung werden Sie die Datenstruktur Verkettete Liste (Linked List) erweitern. + Gegeben sind bereits die Klassen ListNode und LinkedList, sowie einige + Hilfsmethoden: FromPythonlist(inputList) zur Erzeugung einer verketteten Liste aus einer Python-Liste + und printList() zur Ausgabe der Liste. + Ihre Aufgabe ist es, die Funktion mergeTwoLists(list1, list2) + zu implementieren, die zwei sortierte verkettete Listen (Objekte vom Typ LinkedList) zu einer einzigen sortierten Liste zusammenfügt. +

+ +

merge +

+ +

Aufgabe

+ +

+ Implementieren Sie die Funktion mergeTwoLists(list1, list2) außerhalb der Klasse LinkedList. + Die Funktion erhält zwei sortierte LinkedList-Objekte, list1 und list2. + Sie soll die beiden Listen so verknüpfen, dass eine einzige, aufsteigend sortierte Liste entsteht. + Geben Sie ein neues LinkedList-Objekt zurück, das die gemergte Liste enthält. +

+ + +

+ {% include "file.html" %} + Implementieren Sie die Funktion mergeTwoLists in Ihrer Datei. Kopieren Sie dazu den + folgenden Codeblock in die Datei {{filename}}, + und ergänzen Sie die Funktion mergeTwoLists: +

+ +
+

+class ListNode:
+    def __init__(self, value: int):
+        self.value: int = value
+        self.next: ListNode | None = None
+
+
+class LinkedList:
+    def __init__(self):
+        self.head = None
+
+    def FromPythonlist(self, inputList: list[int]):
+        for val in inputList:
+            newNode = ListNode(value=val)
+            self.insertAfterHead(newNode)
+
+    def printList(self):
+        current = self.head
+        while current is not None:
+            print(current.value, end=" -> ")
+            current = current.next
+        print("None")
+
+    def searchValue(self, value: int) -> ListNode | None:
+        # Siehe Problem 'linkedFind.py' für die Implementierung dieser Methode
+        return None
+
+    def insertAfterNode(self, prevNode: ListNode | None, newNode: ListNode):
+        # Siehe Problem 'linkedAfter.py' für die Implementierung dieser Methode
+        return
+
+    def insertAfterLast(self, newNode: ListNode):
+        # Siehe Problem 'linkedInsert.py' für die Implementierung dieser Methode
+        return
+
+    def insertAfterHead(self, newNode: ListNode):
+        newNode.next = self.head
+        self.head = newNode
+
+def mergeTwoLists(list1: LinkedList, list2: LinkedList) -> LinkedList:
+    mergedList = LinkedList()
+    # TODO: Implementieren Sie diese Funktion
+    return mergedList
+
+
+ + + + +{% include "before_you_begin.html" %} + +{% include "how_to_test_head.html" %} + +

+ Testen Sie Ihre Implementierung, indem Sie das Skript ausführen. + Erstellen Sie dazu eine Instanz der LinkedList, fügen Sie Elemente hinzu und rufen Sie dann Ihre Funktion mergeTwoLists auf. + Überprüfen Sie anschließend, ob die Liste die erwartete Struktur hat. +

+ +
+

+  # Erstellen zweier sortierter Listen
+  # Hinweis: FromPythonlist fügt vorne ein, daher umgekehrte Reihenfolge für korrekte Sortierung
+  
+  # Liste 1: 1 -> 2 -> 4
+  ll1 = LinkedList()
+  ll1.FromPythonlist([4, 2, 1])
+  
+  # Liste 2: 1 -> 3 -> 4
+  ll2 = LinkedList()
+  ll2.FromPythonlist([4, 3, 1])
+
+  print("Liste 1:")
+  ll1.printList()
+  print("Liste 2:")
+  ll2.printList()
+
+  # Mergen der Listen
+  merged_list = mergeTwoLists(ll1, ll2)
+
+  print("Gemergte Liste:")
+  merged_list.printList()
+  # Erwartete Ausgabe: 1 -> 1 -> 2 -> 3 -> 4 -> 4 -> None
+
+
+ + + +{% include "how_to_test_auto.html" %} + +{% include "how_to_submit.html" %} + +{% include "how_to_mark_in_moodle.html" %} + +{% include "footer.html" %} \ No newline at end of file diff --git a/linkedRemove/.cs50.yml b/linkedRemove/.cs50.yml new file mode 100644 index 0000000..eb529e8 --- /dev/null +++ b/linkedRemove/.cs50.yml @@ -0,0 +1,10 @@ +submit50: + files: &submit50_files + - !exclude "*" + - !include "*.py" + - !require linkedRemove.py + +check50: + files: *submit50_files + checks: checks/main.py + \ No newline at end of file diff --git a/linkedRemove/checks/__init__.py b/linkedRemove/checks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/linkedRemove/checks/main.py b/linkedRemove/checks/main.py new file mode 100644 index 0000000..90d7518 --- /dev/null +++ b/linkedRemove/checks/main.py @@ -0,0 +1,155 @@ +import check50 +import check50.py + +FILE_NAME = "linkedRemove.py" + + +def to_list(ll): + """LinkedList -> Python-Liste (mit Zyklus-Schutz).""" + out = [] + cur = ll.head + seen = 0 + while cur is not None: + out.append(cur.value) + cur = cur.next + seen += 1 + if seen > 10_000: + msg = f"Linked list appears to have a cycle (more than {seen} nodes)" + raise check50.Failure(msg) + return out + + +def build_ll(module, values): + """Erzeugt eine LinkedList über FromPythonlist (wie in der Aufgabe vorgegeben).""" + ll = module.LinkedList() + ll.FromPythonlist(values) + return ll + + +@check50.check() +def exists(): + """linkedRemove.py exists""" + check50.exists(FILE_NAME) + + +@check50.check(exists) +def compiles(): + """linkedRemove.py compiles""" + check50.py.compile(FILE_NAME) + + +@check50.check(compiles) +def has_classes_and_method(): + """ListNode, LinkedList and removeElement exist""" + module = check50.py.import_(FILE_NAME) + + if not hasattr(module, "ListNode"): + msg = f"Class `ListNode` not found in {FILE_NAME}" + raise check50.Failure(msg) + + if not hasattr(module, "LinkedList"): + msg = f"Class `LinkedList` not found in {FILE_NAME}" + raise check50.Failure(msg) + + if not hasattr(module.LinkedList(), "removeElement"): + msg = "Method `removeElement` not found in Class `LinkedList`" + raise check50.Failure(msg) + + +@check50.check(has_classes_and_method) +def test_remove_middle(): + """removeElement removes a middle node""" + module = check50.py.import_(FILE_NAME) + # List: 30 -> 20 -> 10 + ll = build_ll(module, [10, 20, 30]) + + # Find node with value 20 + node_to_remove = ll.searchValue(20) + if node_to_remove is None: + msg = ( + "searchValue(20) returned None, but 20 should be in the list. " + "Cannot test removeElement." + ) + raise check50.Failure(msg) + + ll.removeElement(node_to_remove) + + expected = [30, 10] + actual = to_list(ll) + + if actual != expected: + raise check50.Mismatch(str(expected), str(actual)) + + +@check50.check(has_classes_and_method) +def test_remove_head(): + """removeElement removes the head node""" + module = check50.py.import_(FILE_NAME) + # List: 30 -> 20 -> 10 + ll = build_ll(module, [10, 20, 30]) + + # Find node with value 30 (head) + node_to_remove = ll.searchValue(30) + if node_to_remove is None: + msg = ( + "searchValue(30) returned None, but 30 should be in the list. " + "Cannot test removeElement." + ) + raise check50.Failure(msg) + + ll.removeElement(node_to_remove) + + expected = [20, 10] + actual = to_list(ll) + + if actual != expected: + raise check50.Mismatch(str(expected), str(actual)) + + +@check50.check(has_classes_and_method) +def test_remove_tail(): + """removeElement removes the tail node""" + module = check50.py.import_(FILE_NAME) + # List: 30 -> 20 -> 10 + ll = build_ll(module, [10, 20, 30]) + + # Find node with value 10 (tail) + node_to_remove = ll.searchValue(10) + if node_to_remove is None: + msg = ( + "searchValue(10) returned None, but 10 should be in the list. " + "Cannot test removeElement." + ) + raise check50.Failure(msg) + + ll.removeElement(node_to_remove) + + expected = [30, 20] + actual = to_list(ll) + + if actual != expected: + raise check50.Mismatch(str(expected), str(actual)) + + +@check50.check(has_classes_and_method) +def test_remove_single_element(): + """removeElement removes the only element in the list""" + module = check50.py.import_(FILE_NAME) + # List: 10 + ll = build_ll(module, [10]) + + node_to_remove = ll.searchValue(10) + if node_to_remove is None: + msg = ( + "searchValue(10) returned None, but 10 should be in the list. " + "Cannot test removeElement." + ) + raise check50.Failure(msg) + + ll.removeElement(node_to_remove) + + expected = [] + actual = to_list(ll) + + if actual != expected: + raise check50.Mismatch(str(expected), str(actual)) diff --git a/linkedRemove/html/linkedRemove.html b/linkedRemove/html/linkedRemove.html new file mode 100644 index 0000000..a99b7e0 --- /dev/null +++ b/linkedRemove/html/linkedRemove.html @@ -0,0 +1,210 @@ +

Linked List: Entferne ein Element aus einer Liste

+ +

+ In dieser Übung werden Sie die Datenstruktur Verkettete Liste (Linked List) erweitern. + Gegeben sind bereits die Klassen ListNode und LinkedList, sowie einige + Hilfsmethoden: FromPythonlist(inputList) zur Erzeugung einer verketteten Liste aus einer Python-Liste + und printList() zur Ausgabe der Liste. + Ihre Aufgabe ist es, die Methode removeElement(node) + zu implementieren, die das übergebene Listenelement node aus der Liste entfernt. +

+ + +

Aufgabe

+ +

+ Implementieren Sie die Methode removeElement(self, node) in der Klasse LinkedList. + Die Methode erhält das Element node, das entfernt werden soll. Sie soll dieses Element aus der Liste entfernen. + Achten Sie darauf, den Vorgänger des Elements korrekt mit dem Nachfolger zu verbinden. + Wenn das Element der Kopf (Head) der Liste ist, muss der Kopf aktualisiert werden. +

+ + +

+ Erstellen Sie eine Datei mit dem Namen + linkedRemove.py und + Implementieren Sie die Methode removeElement in Ihrer Datei. Kopieren Sie dazu den + folgenden Codeblock in die Datei linkedRemove.py, + und ergänzen Sie die Methode removeElement: +

+ +
+

+class ListNode:
+    def __init__(self, value: int):
+        self.value: int = value
+        self.next: ListNode | None = None
+
+
+class LinkedList:
+    def __init__(self):
+        self.head = None
+
+    def FromPythonlist(self, inputList: list[int]):
+        for val in inputList:
+            newNode = ListNode(value=val)
+            self.insertAfterHead(newNode)
+
+    def searchValue(self, value: int) -> ListNode | None:
+        # Siehe Problem 'linkedFind.py' für die Implementierung dieser Methode
+        return None
+
+    def insertAfterNode(self, prevNode: ListNode | None, newNode: ListNode):
+        # Siehe Problem 'linkedAfter.py' für die Implementierung dieser Methode
+        return
+
+    def insertAfterLast(self, newNode: ListNode):
+        # Siehe Problem 'linkedInsert.py' für die Implementierung dieser Methode
+        pass
+
+    def removeElement(self, node: ListNode):
+        # TODO: Implementieren Sie diese Methode
+        pass
+
+    def printList(self):
+        current = self.head
+        while current is not None:
+            print(current.value, end=" -> ")
+            current = current.next
+        print("None")
+
+    def insertAfterHead(self, newNode: ListNode):
+        newNode.next = self.head
+        self.head = newNode
+
+
+ + + + +

Bevor Sie beginnen

+

Melden Sie sich bei cs50.dev an, klicken Sie + auf Ihr Terminal und führen Sie cd ohne Parameter aus. Sie + sollten feststellen, dass der Prompt Ihres Terminals wie unten aussieht:

+
$
+

Als nächstes führen Sie

+
mkdir + linkedRemove
+

aus, um einen Ordner namens linkedRemove in Ihrem Codespace + zu erstellen.

+

Führen Sie anschließend

+
cd + linkedRemove
+

aus, um in dieses Verzeichnis zu wechseln. Der Prompt Ihres Terminals sollte + nun linkedRemove/$ anzeigen. + Jetzt können Sie

+
code + linkedRemove.py
+

ausführen, um eine Datei namens linkedRemove.py zu erstellen, in der Sie Ihr + Programm schreiben. +

+ +

So testen Sie Ihr Programm

+

So können Sie Ihr Programm manuell testen:

+ +

+ Testen Sie Ihre Implementierung, indem Sie das Skript ausführen. + Erstellen Sie dazu eine Instanz der LinkedList, fügen Sie Elemente hinzu und rufen Sie dann Ihre Methode removeElement auf. + Überprüfen Sie anschließend, ob die Liste die erwartete Struktur hat, indem Sie printList() verwenden. +

+ +
+

+  # Erstellen einer verketteten Liste aus einer Python-Liste
+  inputList = [4, 8, 2, 1]
+  ll = LinkedList()
+  ll.FromPythonlist(inputList)
+
+  print("Liste vorher:")
+  ll.printList()
+
+  # Suchen und Entfernen von 8
+  node = ll.searchValue(8)
+  if node:
+      ll.removeElement(node)
+
+  print("Liste nachher:")
+  ll.printList()
+  # Erwartete Ausgabe: 1 -> 2 -> 4 -> None
+
+
+ + + +

Sie können das folgende Kommando ausführen, um Ihren Code mit check50 zu überprüfen, einem Programm, das bei + der Abgabe verwendet wird um Ihren Code zu testen. Testen Sie Ihr Programm + aber auch selbst!

+
+ check50 HSDDigitalLabor/problems/adg2025/linkedRemove +
+

+ Grüne Smileys :) + bedeuten, dass Ihr Programm einen Test bestanden hat! Rote + traurige Smileys :( + zeigen an, dass Ihr Programm etwas Unerwartetes ausgegeben + hat. Besuchen Sie die URL, die check50 + ausgibt, um zu sehen, welche Eingabe check50 + an Ihr Programm übergeben hat, welche Ausgabe erwartet wurde und welche + Ausgabe Ihr Programm tatsächlich geliefert hat. +

+ +

Abgabe

+

Führen Sie im Terminal den folgenden Befehl aus, um Ihre Arbeit einzureichen. +

+
+ submit50 HSDDigitalLabor/problems/adg2025/linkedRemove +
+

+ Führen Sie diesen Befehl vor dem Fälligkeitsdatum aus. Sie können Ihre Lösung + nach dem ersten Einsenden noch ändern und erneut einreichen. Bewertet wird + die zuletzt eingereichte Version vor dem Fälligkeitsdatum. Nach Ablauf der + Frist können Sie technisch zwar noch Abgaben tätigen, Ihre Lösung wird jedoch + nicht mehr gewertet. Das Ergebnis kann ausschließlich mit obigem Befehl abgegeben + werden, eine Abgabe in Moodle ist nicht möglich. +

+ +

Markierung der Aufgabe als erledigt

+

Nach dem Einreichen der Lösung mit submit50, + nehmen Sie eine Pseudolösung in Moodle vor, indem Sie auf den Button + + weiter unten auf dieser Seite betätigen und in das sich öffnende Feld unter + "Texteingabe online" den folgenden Text ein: +

+
+ Mit submit50 abgegeben. +
+

Schließen Sie die Eingabe durch Klick auf den Button + unterhalb des Textfeldes ab. +

+

+ Zur besseren Übersicht markieren Sie das Problem linkedRemove.py in Moodle als erledigt, + indem Sie ganz oben auf dieser Seite den Button +

+

+ + klicken. Daraufhin erscheint der Button + +

+ +

generated 2025-12-22 10:45:25

\ No newline at end of file diff --git a/linkedRemove/html/params.json b/linkedRemove/html/params.json new file mode 100644 index 0000000..49a5feb --- /dev/null +++ b/linkedRemove/html/params.json @@ -0,0 +1,9 @@ +{ + "id": "linkedRemove", + "title": "Linked List: Entferne ein Element aus einer Liste", + "foldername": "linkedRemove", + "filename": "linkedRemove.py", + "asciicast_id": "", + "check50_path": "HSDDigitalLabor/problems/adg2025/linkedRemove", + "submit50_path": "HSDDigitalLabor/problems/adg2025/linkedRemove" +} \ No newline at end of file diff --git a/linkedRemove/html/template.html b/linkedRemove/html/template.html new file mode 100644 index 0000000..0c93d47 --- /dev/null +++ b/linkedRemove/html/template.html @@ -0,0 +1,118 @@ +{% include "header.html" %} + +

+ In dieser Übung werden Sie die Datenstruktur Verkettete Liste (Linked List) erweitern. + Gegeben sind bereits die Klassen ListNode und LinkedList, sowie einige + Hilfsmethoden: FromPythonlist(inputList) zur Erzeugung einer verketteten Liste aus einer Python-Liste + und printList() zur Ausgabe der Liste. + Ihre Aufgabe ist es, die Methode removeElement(node) + zu implementieren, die das übergebene Listenelement node aus der Liste entfernt. +

+ + +

Aufgabe

+ +

+ Implementieren Sie die Methode removeElement(self, node) in der Klasse LinkedList. + Die Methode erhält das Element node, das entfernt werden soll. Sie soll dieses Element aus der Liste entfernen. + Achten Sie darauf, den Vorgänger des Elements korrekt mit dem Nachfolger zu verbinden. + Wenn das Element der Kopf (Head) der Liste ist, muss der Kopf aktualisiert werden. +

+ + +

+ {% include "file.html" %} + Implementieren Sie die Methode removeElement in Ihrer Datei. Kopieren Sie dazu den + folgenden Codeblock in die Datei {{filename}}, + und ergänzen Sie die Methode removeElement: +

+ +
+

+class ListNode:
+    def __init__(self, value: int):
+        self.value: int = value
+        self.next: ListNode | None = None
+
+
+class LinkedList:
+    def __init__(self):
+        self.head = None
+
+    def FromPythonlist(self, inputList: list[int]):
+        for val in inputList:
+            newNode = ListNode(value=val)
+            self.insertAfterHead(newNode)
+
+    def searchValue(self, value: int) -> ListNode | None:
+        # Siehe Problem 'linkedFind.py' für die Implementierung dieser Methode
+        return None
+
+    def insertAfterNode(self, prevNode: ListNode | None, newNode: ListNode):
+        # Siehe Problem 'linkedAfter.py' für die Implementierung dieser Methode
+        return
+
+    def insertAfterLast(self, newNode: ListNode):
+        # Siehe Problem 'linkedInsert.py' für die Implementierung dieser Methode
+        return
+
+    def removeElement(self, node: ListNode):
+        # TODO: Implementieren Sie diese Methode
+        pass
+
+    def printList(self):
+        current = self.head
+        while current is not None:
+            print(current.value, end=" -> ")
+            current = current.next
+        print("None")
+
+    def insertAfterHead(self, newNode: ListNode):
+        newNode.next = self.head
+        self.head = newNode
+
+
+ + + + +{% include "before_you_begin.html" %} + +{% include "how_to_test_head.html" %} + +

+ Testen Sie Ihre Implementierung, indem Sie das Skript ausführen. + Erstellen Sie dazu eine Instanz der LinkedList, fügen Sie Elemente hinzu und rufen Sie dann Ihre Methode removeElement auf. + Überprüfen Sie anschließend, ob die Liste die erwartete Struktur hat, indem Sie printList() verwenden. +

+ +
+

+  # Erstellen einer verketteten Liste aus einer Python-Liste
+  inputList = [4, 8, 2, 1]
+  ll = LinkedList()
+  ll.FromPythonlist(inputList)
+
+  print("Liste vorher:")
+  ll.printList()
+
+  # Suchen und Entfernen von 8
+  node = ll.searchValue(8)
+  if node:
+      ll.removeElement(node)
+
+  print("Liste nachher:")
+  ll.printList()
+  # Erwartete Ausgabe: 1 -> 2 -> 4 -> None
+
+
+ + + +{% include "how_to_test_auto.html" %} + +{% include "how_to_submit.html" %} + +{% include "how_to_mark_in_moodle.html" %} + +{% include "footer.html" %} \ No newline at end of file diff --git a/linkedStack/.cs50.yml b/linkedStack/.cs50.yml new file mode 100644 index 0000000..60f5b04 --- /dev/null +++ b/linkedStack/.cs50.yml @@ -0,0 +1,10 @@ +submit50: + files: &submit50_files + - !exclude "*" + - !include "*.py" + - !require linkedStack.py + +check50: + files: *submit50_files + checks: checks/main.py + \ No newline at end of file diff --git a/linkedStack/checks/__init__.py b/linkedStack/checks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/linkedStack/checks/main.py b/linkedStack/checks/main.py new file mode 100644 index 0000000..628a8c9 --- /dev/null +++ b/linkedStack/checks/main.py @@ -0,0 +1,185 @@ +import check50 +import check50.py + +FILE_NAME = "linkedStack.py" + + +@check50.check() +def exists(): + """linkedStack.py exists""" + check50.exists(FILE_NAME) + + +@check50.check(exists) +def compiles(): + """linkedStack.py compiles""" + check50.py.compile(FILE_NAME) + + +@check50.check(compiles) +def has_classes_and_methods(): + """Classes ListNode, LinkedList, Stack and methods push, pop, peek exist""" + module = check50.py.import_(FILE_NAME) + + if not hasattr(module, "ListNode"): + msg = f"Class `ListNode` not found in {FILE_NAME}" + raise check50.Failure(msg) + + if not hasattr(module, "LinkedList"): + msg = f"Class `LinkedList` not found in {FILE_NAME}" + raise check50.Failure(msg) + + if not hasattr(module, "Stack"): + msg = f"Class `Stack` not found in {FILE_NAME}" + raise check50.Failure(msg) + + stack_instance = module.Stack() + + if not hasattr(stack_instance, "push"): + msg = "Method `push` not found in Class `Stack`" + raise check50.Failure(msg) + if not hasattr(stack_instance, "pop"): + msg = "Method `pop` not found in Class `Stack`" + raise check50.Failure(msg) + if not hasattr(stack_instance, "peek"): + msg = "Method `peek` not found in Class `Stack`" + raise check50.Failure(msg) + + +@check50.check(has_classes_and_methods) +def test_push_peek(): + """push adds element and peek returns it""" + module = check50.py.import_(FILE_NAME) + stack = module.Stack() + + stack.push(10) + top = stack.peek() + + if top != 10: + raise check50.Mismatch( + "10", str(top), help="peek should return the last pushed value" + ) + + +@check50.check(has_classes_and_methods) +def test_push_pop(): + """pop removes and returns the top element""" + module = check50.py.import_(FILE_NAME) + stack = module.Stack() + + stack.push(20) + popped = stack.pop() + + if popped != 20: + raise check50.Mismatch( + "20", str(popped), help="pop should return the last pushed value" + ) + + if stack.peek() is not None: + msg = "Stack should be empty after popping the only element" + raise check50.Failure(msg) + + +@check50.check(has_classes_and_methods) +def test_lifo_order(): + """Stack follows LIFO (Last-In, First-Out) order""" + module = check50.py.import_(FILE_NAME) + stack = module.Stack() + + stack.push(1) + stack.push(2) + stack.push(3) + + if stack.pop() != 3: + msg = "First pop should return 3" + raise check50.Failure(msg) + if stack.pop() != 2: + msg = "Second pop should return 2" + raise check50.Failure(msg) + if stack.pop() != 1: + msg = "Third pop should return 1" + raise check50.Failure(msg) + + +@check50.check(has_classes_and_methods) +def test_empty_stack(): + """pop and peek return None on empty stack""" + module = check50.py.import_(FILE_NAME) + stack = module.Stack() + + if stack.peek() is not None: + msg = "peek on empty stack should return None" + raise check50.Failure(msg) + + if stack.pop() is not None: + msg = "pop on empty stack should return None" + raise check50.Failure(msg) + + +@check50.check(has_classes_and_methods) +def test_mixed_operations(): + """Stack handles mixed push and pop operations correctly""" + module = check50.py.import_(FILE_NAME) + stack = module.Stack() + + stack.push(10) + stack.push(20) + if stack.pop() != 20: + msg = "Pop should return 20" + raise check50.Failure(msg) + + stack.push(30) + if stack.pop() != 30: + msg = "Pop should return 30" + raise check50.Failure(msg) + + if stack.pop() != 10: + msg = "Pop should return 10" + raise check50.Failure(msg) + + if stack.pop() is not None: + msg = "Pop on empty stack should return None" + raise check50.Failure(msg) + + +@check50.check(has_classes_and_methods) +def test_peek_idempotent(): + """peek returns the same value multiple times without removing it""" + module = check50.py.import_(FILE_NAME) + stack = module.Stack() + + stack.push(42) + + val1 = stack.peek() + val2 = stack.peek() + + if val1 != 42 or val2 != 42: + msg = "peek should return 42 consistently" + raise check50.Failure(msg) + + if stack.pop() != 42: + msg = "Item should still be on stack after peek" + raise check50.Failure(msg) + + +@check50.check(has_classes_and_methods) +def test_independent_stacks(): + """Multiple Stack instances are independent""" + module = check50.py.import_(FILE_NAME) + stack1 = module.Stack() + stack2 = module.Stack() + + stack1.push(1) + stack2.push(2) + + if stack1.peek() != 1: + msg = "stack1 should have 1 at top" + raise check50.Failure(msg) + if stack2.peek() != 2: + msg = "stack2 should have 2 at top" + raise check50.Failure(msg) + + stack1.pop() + if stack2.peek() != 2: + msg = "stack2 should still have 2 after popping stack1" + raise check50.Failure(msg) diff --git a/linkedStack/html/generate_png.py b/linkedStack/html/generate_png.py new file mode 100644 index 0000000..3f5aceb --- /dev/null +++ b/linkedStack/html/generate_png.py @@ -0,0 +1,80 @@ +import os +import matplotlib.pyplot as plt +from matplotlib.patches import Rectangle, FancyArrowPatch + + +def draw_stack_colored(items, title="Stack - (Last In, First Out)"): + # smaller figure + smaller cells + w, h = 2.1, 0.6 + x0, y0 = 0.9, 0.6 + + fig, ax = plt.subplots(figsize=(4.0, 2.5)) + + # pastel-ish colors cycling + colors = ["#CFE8FF", "#DFF7D9", "#FFF2CC", "#F8D7DA", "#E7D7FF", "#D1F2EB"] + + # Draw stack cells (bottom to top) + for i, item in enumerate(items): + y = y0 + i * h + face = colors[i % len(colors)] + rect = Rectangle( + (x0, y), w, h, linewidth=1.8, edgecolor="black", facecolor=face + ) + ax.add_patch(rect) + ax.text( + x0 + w / 2, + y + h / 2, + str(item), + ha="center", + va="center", + fontsize=12, + weight="bold", + ) + + # Frame around stack + frame = Rectangle((x0, y0), w, max(len(items), 1) * h, fill=False, linewidth=1.8) + ax.add_patch(frame) + + # Top pointer + top_y = y0 + (len(items) - 1) * h + h / 2 if items else y0 + h / 2 + arrow = FancyArrowPatch( + (x0 + w + 0.9, top_y), + (x0 + w + 0.03, top_y), + arrowstyle="-|>", + mutation_scale=14, + linewidth=1.8, + color="black", + ) + ax.add_patch(arrow) + ax.text(x0 + w + 0.95, top_y, "top", ha="left", va="center", fontsize=10) + + # Optional push/pop mini labels + ax.text( + x0 + w + 0.85, + top_y + 0.35, + r"$\uparrow$ Push()", + ha="center", + va="center", + fontsize=9, + ) + ax.text( + x0 + w + 0.85, + top_y - 0.35, + r"$\downarrow$ Pop()", + ha="center", + va="center", + fontsize=9, + ) + + # Styling + ax.set_xlim(0, x0 + w + 1.6) + ax.set_ylim(0, y0 + max(len(items), 1) * h + 0.9) + ax.axis("off") + + script_dir = os.path.dirname(os.path.abspath(__file__)) + plt.savefig( + os.path.join(script_dir, "stack_graphic.png"), dpi=200, bbox_inches="tight" + ) + + +draw_stack_colored(["14", "67", "43", "8"]) diff --git a/linkedStack/html/linkedStack.html b/linkedStack/html/linkedStack.html new file mode 100644 index 0000000..b8b4c8e --- /dev/null +++ b/linkedStack/html/linkedStack.html @@ -0,0 +1,221 @@ +

Stack mit verketteter Liste implementieren

+ +

+ In dieser Übung werden Sie die Datenstruktur Verkettete Liste (Linked List) verwenden, um einen Stack (Stapel) zu implementieren. + Gegeben sind bereits die Klassen ListNode und LinkedList. + Ihre Aufgabe ist es, die Klasse Stack zu implementieren, die intern eine LinkedList verwendet, um die Stack-Operationen durchzuführen. +

+ +

Stack +

+ +

Aufgabe

+ +

+ Implementieren Sie die Klasse Stack mit den folgenden Methoden: +

+ Nutzen Sie für die Implementierung die Methoden der Klasse LinkedList. +

+ + +

+ Erstellen Sie eine Datei mit dem Namen + linkedStack.py und + Implementieren Sie die Klasse Stack in Ihrer Datei. Kopieren Sie dazu den + folgenden Codeblock in die Datei linkedStack.py, + und ergänzen Sie die fehlenden Methoden: +

+ +
+

+class ListNode:
+    def __init__(self, value: int):
+        self.value: int = value
+        self.next: ListNode | None = None
+
+
+class LinkedList:
+    def __init__(self):
+        self.head = None
+
+    def insertAfterHead(self, newNode: ListNode):
+        newNode.next = self.head
+        self.head = newNode
+
+    def removeAfterHead(self):
+        # TODO: Eine hilfreiche Methode zum Erstellen eines Stacks
+
+    def printList(self):
+        current = self.head
+        while current is not None:
+            print(current.value, end=" -> ")
+            current = current.next
+        print("None")
+
+
+class Stack:
+    def __init__(self):
+        self.ll = LinkedList()
+
+    def push(self, value: int):
+        # TODO: Implementieren Sie diese Methode
+        pass
+
+    def pop(self) -> int | None:
+        # TODO: Implementieren Sie diese Methode
+        pass
+
+    def peek(self) -> int | None:
+        # TODO: Implementieren Sie diese Methode
+        pass
+
+
+ + + + +

Bevor Sie beginnen

+

Melden Sie sich bei cs50.dev an, klicken Sie + auf Ihr Terminal und führen Sie cd ohne Parameter aus. Sie + sollten feststellen, dass der Prompt Ihres Terminals wie unten aussieht:

+
$
+

Als nächstes führen Sie

+
mkdir + linkedStack
+

aus, um einen Ordner namens linkedStack in Ihrem Codespace + zu erstellen.

+

Führen Sie anschließend

+
cd + linkedStack
+

aus, um in dieses Verzeichnis zu wechseln. Der Prompt Ihres Terminals sollte + nun linkedStack/$ anzeigen. + Jetzt können Sie

+
code + linkedStack.py
+

ausführen, um eine Datei namens linkedStack.py zu erstellen, in der Sie Ihr + Programm schreiben. +

+ +

So testen Sie Ihr Programm

+

So können Sie Ihr Programm manuell testen:

+ +

+ Testen Sie Ihre Implementierung, indem Sie das Skript ausführen. + Erstellen Sie dazu eine Instanz der Klasse Stack, führen Sie einige Operationen durch und überprüfen Sie die Ausgaben. +

+ +
+

+  stack = Stack()
+  
+  print("Push 10, 20, 30")
+  stack.push(10)
+  stack.push(20)
+  stack.push(30)
+  
+  print("Stack Inhalt (via LinkedList):")
+  stack.ll.printList()
+  # Erwartet: 30 -> 20 -> 10 -> None
+  
+  print(f"Peek: {stack.peek()}")
+  # Erwartet: 30
+  
+  print(f"Pop: {stack.pop()}")
+  # Erwartet: 30
+  
+  print("Stack Inhalt nach Pop:")
+  stack.ll.printList()
+  # Erwartet: 20 -> 10 -> None
+  
+  print(f"Pop: {stack.pop()}")
+  print(f"Pop: {stack.pop()}")
+  print(f"Pop (leer): {stack.pop()}")
+  # Erwartet: 20, 10, None
+
+
+ + + +

Sie können das folgende Kommando ausführen, um Ihren Code mit check50 zu überprüfen, einem Programm, das bei + der Abgabe verwendet wird um Ihren Code zu testen. Testen Sie Ihr Programm + aber auch selbst!

+
+ check50 HSDDigitalLabor/problems/adg2025/linkedStack +
+

+ Grüne Smileys :) + bedeuten, dass Ihr Programm einen Test bestanden hat! Rote + traurige Smileys :( + zeigen an, dass Ihr Programm etwas Unerwartetes ausgegeben + hat. Besuchen Sie die URL, die check50 + ausgibt, um zu sehen, welche Eingabe check50 + an Ihr Programm übergeben hat, welche Ausgabe erwartet wurde und welche + Ausgabe Ihr Programm tatsächlich geliefert hat. +

+ +

Abgabe

+

Führen Sie im Terminal den folgenden Befehl aus, um Ihre Arbeit einzureichen. +

+
+ submit50 HSDDigitalLabor/problems/adg2025/linkedStack +
+

+ Führen Sie diesen Befehl vor dem Fälligkeitsdatum aus. Sie können Ihre Lösung + nach dem ersten Einsenden noch ändern und erneut einreichen. Bewertet wird + die zuletzt eingereichte Version vor dem Fälligkeitsdatum. Nach Ablauf der + Frist können Sie technisch zwar noch Abgaben tätigen, Ihre Lösung wird jedoch + nicht mehr gewertet. Das Ergebnis kann ausschließlich mit obigem Befehl abgegeben + werden, eine Abgabe in Moodle ist nicht möglich. +

+ +

Markierung der Aufgabe als erledigt

+

Nach dem Einreichen der Lösung mit submit50, + nehmen Sie eine Pseudolösung in Moodle vor, indem Sie auf den Button + + weiter unten auf dieser Seite betätigen und in das sich öffnende Feld unter + "Texteingabe online" den folgenden Text ein: +

+
+ Mit submit50 abgegeben. +
+

Schließen Sie die Eingabe durch Klick auf den Button + unterhalb des Textfeldes ab. +

+

+ Zur besseren Übersicht markieren Sie das Problem linkedStack.py in Moodle als erledigt, + indem Sie ganz oben auf dieser Seite den Button +

+

+ + klicken. Daraufhin erscheint der Button + +

+ +

generated 2025-12-22 12:14:08

\ No newline at end of file diff --git a/linkedStack/html/params.json b/linkedStack/html/params.json new file mode 100644 index 0000000..d899a42 --- /dev/null +++ b/linkedStack/html/params.json @@ -0,0 +1,9 @@ +{ + "id": "linkedStack", + "title": "Stack mit verketteter Liste implementieren", + "foldername": "linkedStack", + "filename": "linkedStack.py", + "asciicast_id": "", + "check50_path": "HSDDigitalLabor/problems/adg2025/linkedStack", + "submit50_path": "HSDDigitalLabor/problems/adg2025/linkedStack" +} \ No newline at end of file diff --git a/linkedStack/html/stack_graphic.png b/linkedStack/html/stack_graphic.png new file mode 100644 index 0000000..ae6bc2a Binary files /dev/null and b/linkedStack/html/stack_graphic.png differ diff --git a/linkedStack/html/template.html b/linkedStack/html/template.html new file mode 100644 index 0000000..d7094cd --- /dev/null +++ b/linkedStack/html/template.html @@ -0,0 +1,129 @@ +{% include "header.html" %} + +

+ In dieser Übung werden Sie die Datenstruktur Verkettete Liste (Linked List) verwenden, um einen Stack (Stapel) zu implementieren. + Gegeben sind bereits die Klassen ListNode und LinkedList. + Ihre Aufgabe ist es, die Klasse Stack zu implementieren, die intern eine LinkedList verwendet, um die Stack-Operationen durchzuführen. +

+ +

Stack +

+ +

Aufgabe

+ +

+ Implementieren Sie die Klasse Stack mit den folgenden Methoden: +

+ Nutzen Sie für die Implementierung die Methoden der Klasse LinkedList. +

+ + +

+ {% include "file.html" %} + Implementieren Sie die Klasse Stack in Ihrer Datei. Kopieren Sie dazu den + folgenden Codeblock in die Datei {{filename}}, + und ergänzen Sie die fehlenden Methoden: +

+ +
+

+class ListNode:
+    def __init__(self, value: int):
+        self.value: int = value
+        self.next: ListNode | None = None
+
+
+class LinkedList:
+    def __init__(self):
+        self.head = None
+
+    def insertAfterHead(self, newNode: ListNode):
+        newNode.next = self.head
+        self.head = newNode
+
+    def removeAfterHead(self):
+        # TODO: Eine hilfreiche Methode zum Erstellen eines Stacks
+
+    def printList(self):
+        current = self.head
+        while current is not None:
+            print(current.value, end=" -> ")
+            current = current.next
+        print("None")
+
+
+class Stack:
+    def __init__(self):
+        self.ll = LinkedList()
+
+    def push(self, value: int):
+        # TODO: Implementieren Sie diese Methode
+        pass
+
+    def pop(self) -> int | None:
+        # TODO: Implementieren Sie diese Methode
+        pass
+
+    def peek(self) -> int | None:
+        # TODO: Implementieren Sie diese Methode
+        pass
+
+
+ + + + +{% include "before_you_begin.html" %} + +{% include "how_to_test_head.html" %} + +

+ Testen Sie Ihre Implementierung, indem Sie das Skript ausführen. + Erstellen Sie dazu eine Instanz der Klasse Stack, führen Sie einige Operationen durch und überprüfen Sie die Ausgaben. +

+ +
+

+  stack = Stack()
+  
+  print("Push 10, 20, 30")
+  stack.push(10)
+  stack.push(20)
+  stack.push(30)
+  
+  print("Stack Inhalt (via LinkedList):")
+  stack.ll.printList()
+  # Erwartet: 30 -> 20 -> 10 -> None
+  
+  print(f"Peek: {stack.peek()}")
+  # Erwartet: 30
+  
+  print(f"Pop: {stack.pop()}")
+  # Erwartet: 30
+  
+  print("Stack Inhalt nach Pop:")
+  stack.ll.printList()
+  # Erwartet: 20 -> 10 -> None
+  
+  print(f"Pop: {stack.pop()}")
+  print(f"Pop: {stack.pop()}")
+  print(f"Pop (leer): {stack.pop()}")
+  # Erwartet: 20, 10, None
+
+
+ + + +{% include "how_to_test_auto.html" %} + +{% include "how_to_submit.html" %} + +{% include "how_to_mark_in_moodle.html" %} + +{% include "footer.html" %} \ No newline at end of file