Skip to content

Commit 6fcb23f

Browse files
committed
add Problem "linkedAfter"
1 parent 9570e8c commit 6fcb23f

6 files changed

Lines changed: 482 additions & 0 deletions

File tree

‎linkedAfter/.cs50.yml‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
submit50:
2+
files: &submit50_files
3+
- !exclude "*"
4+
- !include "*.py"
5+
- !require linkedAfter.py
6+
7+
check50:
8+
files: *submit50_files
9+
checks: checks/main.py
10+

‎linkedAfter/checks/__init__.py‎

Whitespace-only changes.

‎linkedAfter/checks/main.py‎

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import check50
2+
import check50.py
3+
4+
FILE_NAME = "linkedAfter.py"
5+
6+
7+
def to_list(ll):
8+
"""LinkedList -> Python-Liste (mit Zyklus-Schutz)."""
9+
out = []
10+
cur = ll.head
11+
seen = 0
12+
while cur is not None:
13+
out.append(cur.value)
14+
cur = cur.next
15+
seen += 1
16+
if seen > 10_000:
17+
msg = f"Linked list appears to have a cycle (more than {seen} nodes)"
18+
raise check50.Failure(msg)
19+
return out
20+
21+
22+
def build_ll(module, values):
23+
"""Erzeugt eine LinkedList über FromPythonlist (wie in der Aufgabe vorgegeben)."""
24+
ll = module.LinkedList()
25+
ll.FromPythonlist(values)
26+
return ll
27+
28+
29+
@check50.check()
30+
def exists():
31+
"""linkedAfter.py exists"""
32+
check50.exists(FILE_NAME)
33+
34+
35+
@check50.check(exists)
36+
def compiles():
37+
"""linkedAfter.py compiles"""
38+
check50.py.compile(FILE_NAME)
39+
40+
41+
@check50.check(compiles)
42+
def has_classes_and_method():
43+
"""ListNode, LinkedList and insertAfterNode exist"""
44+
module = check50.py.import_(FILE_NAME)
45+
46+
if not hasattr(module, "ListNode"):
47+
msg = f"Class `ListNode` not found in {FILE_NAME}"
48+
raise check50.Failure(msg)
49+
50+
if not hasattr(module, "LinkedList"):
51+
msg = f"Class `LinkedList` not found in {FILE_NAME}"
52+
raise check50.Failure(msg)
53+
54+
if not hasattr(module.LinkedList(), "insertAfterNode"):
55+
msg = "Method `insertAfterNode` not found in Class `LinkedList`"
56+
raise check50.Failure(msg)
57+
58+
59+
@check50.check(has_classes_and_method)
60+
def test_frompythonlist_order_is_head_insertion():
61+
"""FromPythonlist: inserts after head (result is reversed input order)"""
62+
module = check50.py.import_(FILE_NAME)
63+
64+
ll = build_ll(module, [1, 2, 8, 4])
65+
expected = [4, 8, 2, 1] # weil insertAfterHead bei Vorwärtsiteration umdreht
66+
actual = to_list(ll)
67+
68+
if actual != expected:
69+
raise check50.Mismatch(str(expected), str(actual))
70+
71+
72+
@check50.check(has_classes_and_method)
73+
def test_insert_after_middle():
74+
"""insertAfterNode inserts after a middle node (in reversed-built list)"""
75+
module = check50.py.import_(FILE_NAME)
76+
77+
ll = build_ll(module, [1, 2, 8, 4]) # Liste: 4 -> 8 -> 2 -> 1
78+
node = ll.searchValue(8)
79+
if node is None:
80+
msg = "searchValue(8) returned None, but 8 should be in the list"
81+
raise check50.Failure(msg)
82+
83+
ll.insertAfterNode(node, module.ListNode(3))
84+
85+
expected = [4, 8, 3, 2, 1]
86+
actual = to_list(ll)
87+
if actual != expected:
88+
raise check50.Mismatch(str(expected), str(actual))
89+
90+
91+
@check50.check(has_classes_and_method)
92+
def test_insert_after_head():
93+
"""insertAfterNode inserts after head"""
94+
module = check50.py.import_(FILE_NAME)
95+
96+
ll = build_ll(module, [10, 20, 30]) # Liste: 30 -> 20 -> 10
97+
head = ll.head
98+
if head is None:
99+
msg = "Linked list head is None after FromPythonlist"
100+
raise check50.Failure(msg)
101+
102+
ll.insertAfterNode(head, module.ListNode(25))
103+
104+
expected = [30, 25, 20, 10]
105+
actual = to_list(ll)
106+
if actual != expected:
107+
raise check50.Mismatch(str(expected), str(actual))
108+
109+
110+
@check50.check(has_classes_and_method)
111+
def test_insert_after_tail():
112+
"""insertAfterNode inserts after last node (tail)"""
113+
module = check50.py.import_(FILE_NAME)
114+
115+
ll = build_ll(module, [10, 20, 30]) # Liste: 30 -> 20 -> 10
116+
tail = ll.searchValue(10) # 10 ist Tail
117+
if tail is None:
118+
msg = "searchValue(10) returned None, but 10 should be in the list"
119+
raise check50.Failure(msg)
120+
121+
ll.insertAfterNode(tail, module.ListNode(5))
122+
123+
expected = [30, 20, 10, 5]
124+
actual = to_list(ll)
125+
if actual != expected:
126+
raise check50.Mismatch(str(expected), str(actual))
127+
128+
129+
@check50.check(has_classes_and_method)
130+
def test_insert_after_none_prevnode():
131+
"""insertAfterNode with prevNode=None:
132+
We expect an exception (ValueError) rather than silently doing nothing."""
133+
module = check50.py.import_(FILE_NAME)
134+
135+
ll = build_ll(module, [1, 2, 3])
136+
prev = ll.searchValue(999) # not in list -> None
137+
new_node = module.ListNode(4)
138+
139+
threw = False
140+
try:
141+
ll.insertAfterNode(prev, new_node)
142+
except ValueError:
143+
threw = True
144+
145+
if not threw:
146+
msg = "insertAfterNode should raise an ValueError when prevNode is None"
147+
raise check50.Failure(msg)

‎linkedAfter/html/linkedAfter.html‎

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
<h1 id="linkedAfter">Linked List: Insert After Node</h1>
2+
3+
<p>
4+
In dieser Übung werden Sie die Datenstruktur <strong>Verkettete Liste (Linked List)</strong> erweitern.
5+
Gegeben sind bereits die Klassen <code>ListNode</code> und <code>LinkedList</code>, sowie einige
6+
Hilfsmethoden zur Erzeugung einer verkettenten Liste aus eine Python Liste <code>FromPythonlist(inputList)</code>
7+
und der Methode zur Ausgabe einer verketteten Liste <code>printList()</code>. Eine weitere Methode ist
8+
<code>searchValue(value)</code> mit deren Hilfe Sie eine Listenelement mit einem bestimmten Wert
9+
suchen können. Ihre Aufgabe ist es, eine Methode <code>insertAfterNode(prevNode, newNode)</code>
10+
zu implementieren, die ein neues Listenelement <code>newNode</code> direkt nach dem gegebenen
11+
Element <code>prevNode</code> einfügt.
12+
</p>
13+
14+
15+
<h2 id="aufgabe">Aufgabe</h2>
16+
17+
<p>
18+
Implementieren Sie die Funktion <code>insertAfterNode</code> in Python.
19+
Die Funktion bekommt das Element <code>prevNode</code> und das neue Element <code>newNode</code>
20+
übergeben und soll das neue Element in die Liste einfügen. Ist <code>prevNode</code> None,
21+
soll eine <code>ValueError</code> Exception ausgelöst werden.
22+
</p>
23+
24+
25+
<p>
26+
Erstellen Sie eine Datei mit dem Namen
27+
<code class="text-danger border border-dark">linkedAfter.py</code> und
28+
Implementieren Sie die Funktion <code>insertAfterNode</code> in Ihrer Datei. Kopieren Sie dazu den
29+
folgenden Codeblock in die Datei <code class="text-danger border border-dark">linkedAfter.py</code>,
30+
und ergänzen Sie die Methode <code>insertAfterNode</code>:
31+
</p>
32+
33+
<div class="alert alert-dark">
34+
<pre><code>
35+
class ListNode:
36+
def __init__(self, value: int):
37+
self.value: int = value
38+
self.next: ListNode | None = None
39+
40+
41+
class LinkedList:
42+
def __init__(self):
43+
self.head = None
44+
45+
def FromPythonlist(self, inputList: list[int]):
46+
for val in inputList:
47+
newNode = ListNode(value=val)
48+
self.insertAfterHead(newNode)
49+
50+
def searchValue(self, value: int) -> ListNode:
51+
current = self.head
52+
while current is not None:
53+
if current.value == value:
54+
return current
55+
current = current.next
56+
return None
57+
58+
def printList(self):
59+
current = self.head
60+
while current is not None:
61+
print(current.value, end=" -> ")
62+
current = current.next
63+
print("None")
64+
65+
def insertAfterHead(self, newNode: ListNode):
66+
newNode.next = self.head
67+
self.head = newNode
68+
</code></pre>
69+
</div>
70+
71+
72+
<!-- <p></p>
73+
<h2 id="demo">Demo</h2>
74+
<p>
75+
<script async="" data-autoplay="1" data-cols="80" data-loop="1" data-rows="12"
76+
id="asciicast-"
77+
src="https://asciinema.org/a/.js">
78+
</script>
79+
</p> -->
80+
81+
<h2 id="before-you-begin">Bevor Sie beginnen</h2>
82+
<p>Melden Sie sich bei <a href="https://cs50.dev/" target="_blank">cs50.dev</a> an, klicken Sie
83+
auf Ihr Terminal und führen Sie <code
84+
class="text-danger border border-dark">cd</code> ohne Parameter aus. Sie
85+
sollten feststellen, dass der Prompt Ihres Terminals wie unten aussieht:</p>
86+
<div class="alert alert-primary"><code
87+
class="text-dark font-weight-bold">$</code></div>
88+
<p>Als nächstes führen Sie</p>
89+
<div class="alert alert-primary"><code class="text-dark font-weight-bold">mkdir
90+
linkedAfter</code></div>
91+
<p>aus, um einen Ordner namens <code
92+
class="text-danger border border-dark">linkedAfter</code> in Ihrem Codespace
93+
zu erstellen.</p>
94+
<p>Führen Sie anschließend</p>
95+
<div class="alert alert-primary"><code class="text-dark font-weight-bold">cd
96+
linkedAfter</code></div>
97+
<p>aus, um in dieses Verzeichnis zu wechseln. Der Prompt Ihres Terminals sollte
98+
nun <code class="text-danger border border-dark">linkedAfter/$</code> anzeigen.
99+
Jetzt können Sie</p>
100+
<div class="alert alert-primary"><code class="text-dark font-weight-bold">code
101+
linkedAfter.py</code></div>
102+
<p>ausführen, um eine Datei namens <code
103+
class="text-danger">linkedAfter.py</code> zu erstellen, in der Sie Ihr
104+
Programm schreiben.
105+
</p>
106+
107+
<h2 id="how-to-test">So testen Sie Ihr Programm</h2>
108+
<p>So können Sie Ihr Programm manuell testen:</p>
109+
110+
<p>
111+
Testen Sie Ihre Implementierung, indem Sie das Skript ausführen.
112+
Erstellen Sie dazu eine Instanz der <code>LinkedList</code>, fügen Sie Elemente hinzu und rufen Sie dann Ihre Methode <code>insertAfterNode</code> auf.
113+
Überprüfen Sie anschließend, ob die Liste die erwartete Struktur hat, indem Sie <code>printList()</code> verwenden.
114+
</p>
115+
116+
<div class="alert alert-dark">
117+
<pre><code>
118+
# Erstellen einer verketteten Liste aus einer Python-Liste
119+
inputList = [4, 8, 2, 1]
120+
ll = LinkedList()
121+
ll.FromPythonlist(inputList)
122+
123+
print("Liste vorher:")
124+
ll.printList()
125+
126+
node = ll.searchValue(8)
127+
newNode = ListNode(3)
128+
# Einfügen von 3 nach 8
129+
ll.insertAfterNode(node, newNode)
130+
131+
print("Liste nachher:")
132+
ll.printList()
133+
# Erwartete Ausgabe: 1 -> 2 -> 8 -> 3 -> 4 -> None
134+
</code></pre>
135+
</div>
136+
137+
138+
139+
<p>Sie können das folgende Kommando ausführen, um Ihren Code mit <code
140+
class="text-danger">check50</code> zu überprüfen, einem Programm, das bei
141+
der Abgabe verwendet wird um Ihren Code zu testen. Testen Sie Ihr Programm
142+
aber auch selbst!</p>
143+
<div class="alert alert-primary"><code class="text-dark font-weight-bold">
144+
check50 HSDDigitalLabor/problems/adg2025/linkedAfter
145+
</code></div>
146+
<p>
147+
Grüne Smileys <span style="font-family: monospace; color: green;">:) </span>
148+
bedeuten, dass Ihr Programm einen Test bestanden hat! Rote
149+
traurige Smileys <span style="font-family: monospace; color: red;">:( </span>
150+
zeigen an, dass Ihr Programm etwas Unerwartetes ausgegeben
151+
hat. Besuchen Sie die URL, die <code class="text-danger">check50</code>
152+
ausgibt, um zu sehen, welche Eingabe <code class="text-danger">check50</code>
153+
an Ihr Programm übergeben hat, welche Ausgabe erwartet wurde und welche
154+
Ausgabe Ihr Programm tatsächlich geliefert hat.
155+
</p>
156+
157+
<h2 id="how-to-submit">Abgabe</h2>
158+
<p>Führen Sie im Terminal den folgenden Befehl aus, um Ihre Arbeit einzureichen.
159+
</p>
160+
<div class="alert alert-primary"><code class="text-dark font-weight-bold">
161+
submit50 HSDDigitalLabor/problems/adg2025/linkedAfter
162+
</code></div>
163+
<p>
164+
Führen Sie diesen Befehl vor dem Fälligkeitsdatum aus. Sie können Ihre Lösung
165+
nach dem ersten Einsenden noch ändern und erneut einreichen. Bewertet wird
166+
die zuletzt eingereichte Version vor dem Fälligkeitsdatum. Nach Ablauf der
167+
Frist können Sie technisch zwar noch Abgaben tätigen, Ihre Lösung wird jedoch
168+
nicht mehr gewertet. Das Ergebnis kann ausschließlich mit obigem Befehl abgegeben
169+
werden, eine Abgabe in Moodle ist nicht möglich.
170+
</p>
171+
172+
<h2 id="how-to-mark">Markierung der Aufgabe als erledigt</h2>
173+
<p>Nach dem Einreichen der Lösung mit <code class="text-danger">submit50</code>,
174+
nehmen Sie eine Pseudolösung in Moodle vor, indem Sie auf den Button
175+
<button type="submit" class="btn btn-primary" id="sample_solution" disabled>
176+
Aufgabenlösung hinzufügen</button>
177+
weiter unten auf dieser Seite betätigen und in das sich öffnende Feld unter
178+
"Texteingabe online" den folgenden Text ein:
179+
</p>
180+
<div class="alert alert-primary">
181+
<code class="text-dark font-weight-bold">Mit submit50 abgegeben.</code>
182+
</div>
183+
<p>Schließen Sie die Eingabe durch Klick auf den Button
184+
<button type="submit" class="btn btn-primary" id="sample_save" disabled>
185+
Änderungen speichern</button> unterhalb des Textfeldes ab.
186+
</p>
187+
<p>
188+
Zur besseren Übersicht markieren Sie das Problem linkedAfter.py in Moodle als erledigt,
189+
indem Sie ganz oben auf dieser Seite den Button
190+
</p>
191+
<p>
192+
<button class="btn btn-outline-secondary btn-sm text-nowrap" title="Problem: linkedAfter.py als erledigt kennzeichnen"
193+
aria-label="Problem: linkedAfter.py als erledigt kennzeichnen" disabled>
194+
Als erledigt kennzeichnen
195+
</button>
196+
klicken. Daraufhin erscheint der Button
197+
<button class="btn btn-success btn-sm text-nowrap"
198+
title="Problem: linkedAfter.py ist als erledigt gekennzeichnet. Zum Rückgängigmachen klicken."
199+
aria-label="Problem: linkedAfter.py ist als erledigt gekennzeichnet. Zum Rückgängigmachen klicken." disabled>
200+
<i class="fa fa-check" aria-hidden="true"></i> Erledigt
201+
</button>
202+
</p>
203+
204+
<p class="text-muted text-right text-nowrap" style="font-size: 0.6em;">generated 2025-12-19 19:13:17</p>

‎linkedAfter/html/params.json‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"id": "linkedAfter",
3+
"title": "Linked List: Insert After Node",
4+
"foldername": "linkedAfter",
5+
"filename": "linkedAfter.py",
6+
"asciicast_id": "",
7+
"check50_path": "HSDDigitalLabor/problems/adg2025/linkedAfter",
8+
"submit50_path": "HSDDigitalLabor/problems/adg2025/linkedAfter"
9+
}

0 commit comments

Comments
 (0)