diff --git a/iban/html/iban.html b/iban/html/iban.html index f5a4311..42626dc 100644 --- a/iban/html/iban.html +++ b/iban/html/iban.html @@ -118,7 +118,7 @@

Bevor Sie beginnen

Führen Sie anschließend

cd iban
-

aus, um in dieses Verzeichnis zu wechseln. Der Prompt ihres Terminals sollte +

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

code @@ -141,7 +141,7 @@

So testen Sie Ihr Programm


 print(calcCheckDigitsDE(50010517, 123456789))   # Erwartet: 41
 print(calcCheckDigitsDE(50640000, 123456789))   # Erwartet: 45
-print(calcCheckDigitsDE(48590377, 987654321))   # Erwartet: 23
+print(calcCheckDigitsDE(48590377, 987654321))   # Erwartet: 27
     
@@ -185,7 +185,7 @@

Abgabe

Markierung der Aufgabe als erledigt

-

Nachdem Einreichen der Lösung mit submit50, +

Nach dem Einreichen der Lösung mit submit50, nehmen Sie eine Pseudolösung in Moodle vor, indem Sie auf den Button @@ -216,4 +216,4 @@

Markierung der Aufgabe als erledigt

-

generated 2025-10-31 10:41:19

\ No newline at end of file +

generated 2025-12-04 09:18:26

\ No newline at end of file diff --git a/iban/html/template.html b/iban/html/template.html index f546b54..6284991 100644 --- a/iban/html/template.html +++ b/iban/html/template.html @@ -108,7 +108,7 @@

Aufgabe


 print(calcCheckDigitsDE(50010517, 123456789))   # Erwartet: 41
 print(calcCheckDigitsDE(50640000, 123456789))   # Erwartet: 45
-print(calcCheckDigitsDE(48590377, 987654321))   # Erwartet: 23
+print(calcCheckDigitsDE(48590377, 987654321))   # Erwartet: 27
     
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..bedab1e --- /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 a 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 diff --git a/rotate/checks/main.py b/rotate/checks/main.py index c10f073..1d38418 100644 --- a/rotate/checks/main.py +++ b/rotate/checks/main.py @@ -26,12 +26,16 @@ def has_function(): @check50.check(has_function) -def example1(): - """Example 1: rotate_list([1,2,3,4,5,6,7], 3) works""" +def empty_list(): + """empty list is unchanged""" module = check50.py.import_(FILE_NAME) - lst = [1, 2, 3, 4, 5, 6, 7] - module.rotate_list(lst, 3) - expected = [5, 6, 7, 1, 2, 3, 4] + lst = [] + ret = module.rotate_list(lst, 0) + expected = [] + if id(lst) != id(ret): + msg = "got new list, address of list changes" + raise check50.Failure(msg) + if lst != expected: msg = f"expected {expected}, got {lst}" raise check50.Failure(msg) @@ -42,14 +46,29 @@ def zero_rotation(): """Rotation by 0 keeps list unchanged""" module = check50.py.import_(FILE_NAME) lst = [1, 2, 3] - module.rotate_list(lst, 0) + ret = module.rotate_list(lst, 0) expected = [1, 2, 3] + if id(lst) != id(ret): + msg = "expected in-place modification, but got a new list" + raise check50.Failure(msg) + if lst != expected: msg = f"expected {expected}, got {lst}" raise check50.Failure(msg) @check50.check(has_function) +def check_inplace(): + """check list is used in place""" + module = check50.py.import_(FILE_NAME) + lst = [1, 2, 3, 4, 5, 6, 7] + ret = module.rotate_list(lst, 3) + if id(lst) != id(ret): + msg = "expected in-place modification, but got a new list" + raise check50.Failure(msg) + + +@check50.check(check_inplace) def rotation_equal_length(): """Rotation by list length keeps list unchanged""" module = check50.py.import_(FILE_NAME) @@ -61,7 +80,7 @@ def rotation_equal_length(): raise check50.Failure(msg) -@check50.check(has_function) +@check50.check(check_inplace) def rotation_greater_than_length(): """Rotation greater than list length works""" module = check50.py.import_(FILE_NAME) @@ -73,7 +92,7 @@ def rotation_greater_than_length(): raise check50.Failure(msg) -@check50.check(has_function) +@check50.check(check_inplace) def negatives(): """Rotation with negative numbers works""" module = check50.py.import_(FILE_NAME) diff --git a/sudoku2/html/sudoku2.html b/sudoku2/html/sudoku2.html index 34fa8da..1227fd2 100644 --- a/sudoku2/html/sudoku2.html +++ b/sudoku2/html/sudoku2.html @@ -1,7 +1,8 @@

Sudoku 2

-

Suduko Feld

+

Sudoku Feld

Beim Lösen eines Sudoku-Rätsels ist es wichtig sicherzustellen, dass das Sudoku-Feld @@ -20,7 +21,7 @@

Sudoku 2

- Erstellen Sie eine Datei mit dem Namen + Erstellen Sie eine Datei mit dem Namen sudoku.py und Implementieren Sie Ihr Programm so, dass die Funktion isValidBlock(board) korrekt überprüft, @@ -70,13 +71,16 @@

Demo

Bevor Sie beginnen

Melden Sie sich bei cs50.dev an, klicken Sie - auf Ihr Terminal und führen Sie cd ohne Parameter aus. 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 sudoku2
-

aus, um einen Ordner namens sudoku2 in Ihrem Codespace +

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

Führen Sie anschließend

cd @@ -86,7 +90,8 @@

Bevor Sie beginnen

Jetzt können Sie

code sudoku.py
-

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

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

@@ -139,8 +144,8 @@

So testen Sie Ihr Programm

-

Sie können das folgende Kommando ausführen, um Ihren Code mit check50 zu überprüfen, - einem Programm, das bei +

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!

@@ -204,4 +209,4 @@

Markierung der Aufgabe als erledigt

-

generated 2025-12-01 13:17:52

\ No newline at end of file +

generated 2025-12-10 08:37:17

\ No newline at end of file diff --git a/sudoku2/html/template.html b/sudoku2/html/template.html index 871040a..e9b9914 100644 --- a/sudoku2/html/template.html +++ b/sudoku2/html/template.html @@ -1,7 +1,8 @@ {% include "header.html" %} -

Suduko Feld

+

Sudoku Feld

Beim Lösen eines Sudoku-Rätsels ist es wichtig sicherzustellen, dass das Sudoku-Feld @@ -13,7 +14,7 @@

- Ihre Aufgabe ist es, eine Funktion isValid(board) + Ihre Aufgabe ist es, eine Funktion isValidBlock(board) zu implementieren, die ein 9x9-Sudoku-Board (als Liste von Listen mit Strings) entgegennimmt und True zurückgibt, wenn alle 3x3-Blocks gültig sind, ansonsten False. Leere Felder sind durch "." dargestellt. @@ -22,7 +23,7 @@

{% include "file.html" %} Implementieren Sie Ihr Programm so, dass die Funktion - isValid(board) korrekt überprüft, + isValidBlock(board) korrekt überprüft, ob jedes 3x3-Subgrid die Regeln erfüllt.

@@ -66,7 +67,7 @@
  • Ihr Programm wird nicht über Eingaben getestet, sondern ausschließlich - über Aufrufe der Funktion isValid mit verschiedenen Sudoku-Boards. + über Aufrufe der Funktion isValidBlock mit verschiedenen Sudoku-Boards.
  • diff --git a/zeilen/checks/main.py b/zeilen/checks/main.py index 2b8161e..563aee1 100644 --- a/zeilen/checks/main.py +++ b/zeilen/checks/main.py @@ -142,6 +142,58 @@ def test_rowMult_example_2(): raise check50.Failure(msg) +@check50.check(has_rowMult_function) +def test_rowMult_example_3(): + """rowMult(M, 0, 3): multiply 1st row by 3 (example 3)""" + module = check50.py.import_(FILE_NAME) + + M = [ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + [13, 14, 15, 16], + ] + + module.rowMult(M, 0, 3) + + expected = [ + [3, 6, 9, 12], + [5, 6, 7, 8], + [9, 10, 11, 12], + [13, 14, 15, 16], + ] + + if expected != M: + msg = pretty_matrix_diff(expected, M) + raise check50.Failure(msg) + + +@check50.check(has_rowMult_function) +def test_rowMult_example_4(): + """rowMult(M, 3, 2): multiply 4th row by 2 (example 4)""" + module = check50.py.import_(FILE_NAME) + + M = [ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + [13, 14, 15, 16], + ] + + module.rowMult(M, 3, 2) + + expected = [ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + [26, 28, 30, 32], + ] + + if expected != M: + msg = pretty_matrix_diff(expected, M) + raise check50.Failure(msg) + + @check50.check(has_rowMult_function) def rowMult_invalid_indices(): """rowMult(): ignores invalid indices"""