Informatik

Verkettete Listen: Aufbau und Laufzeiten

Verkettete Listen: Aufbau und Laufzeiten
Verkettete Listen: Aufbau und Laufzeiten
Für Quiz, Lückentext, Lernkarten und Fortschritt ist JavaScript nötig. Alle Inhalte und Lösungen bleiben direkt lesbar.

Eine verkettete Liste speichert geordnete Daten in einzelnen Knoten. Jeder Knoten verweist auf den nächsten Knoten; deshalb müssen die Knoten nicht nebeneinander im Speicher liegen. Du kannst eine Liste dynamisch vergrößern, erreichst eine bestimmte Position aber nur durch schrittweises Durchlaufen.

Deine Lernziele

Hake ab, was du schon kannst — und komm am Ende hierher zurück!

Was macht eine verkettete Liste aus?

Stell dir die Zahlenfolge 7, 4, 9 als Kette vor:

Kopf → 7 → 4 → 9 → NULL

Der Kopf ist der gespeicherte Zugang zum ersten Knoten. NULL kennzeichnet hier das Ende der Liste.

Definition

Knoten

Ein Knoten enthält Nutzdaten und mindestens einen Verweis. In einer einfach verketteten Liste zeigt dieser Verweis auf den nächsten Knoten.

Die Reihenfolge entsteht durch die Verweise, nicht durch benachbarte Speicherplätze. Der Knoten mit 7 kann daher an einer ganz anderen Speicherstelle liegen als der Knoten mit 4.

Eine leere Liste besitzt keinen Datenknoten. Ihr Kopf verweist unmittelbar auf NULL. Bei einer Liste mit genau einem Datenknoten zeigt der Kopf auf diesen Knoten und dessen Nachfolger auf NULL.

Teste dich
Frage 1 von 1LeichtWelche Angabe bestimmt die logische Reihenfolge einer einfach verketteten Liste?
Lösung: Die Nachfolgerverweise der Knoten — Die Knoten dürfen verteilt im Speicher liegen. Erst ihre Nachfolgerverweise verbinden sie zu einer geordneten Liste.
Wie fügst du einen Knoten ein?

In die Liste 7 → 4 → NULL soll der Wert 5 zwischen 7 und 4 eingefügt werden.

Beispiel
  1. Erzeuge den neuen Knoten 5.
  2. Setze den Nachfolger von 5 auf den bisherigen Nachfolger von 7, also auf 4.
  3. Setze anschließend den Nachfolger von 7 auf 5.

Das Ergebnis lautet: 7 → 5 → 4 → NULL.

Die Reihenfolge der Änderungen ist entscheidend. Würdest du zuerst den Verweis von 7 überschreiben, könntest du den Zugang zu 4 und zum restlichen Listenteil verlieren.

Am Anfang ist kein Vorgängerknoten vorhanden. Deshalb wird zuerst der Nachfolger des neuen Knotens auf den bisherigen ersten Knoten gesetzt. Danach wird der Kopf auf den neuen Knoten umgestellt.

Merke

Beim Einfügen sicherst du zuerst den Zugang zum bisherigen Nachfolger. Erst danach leitest du den Vorgänger oder den Kopf auf den neuen Knoten um.

Teste dich
Frage 1 von 1MittelIn A → B → C soll X zwischen A und B eingefügt werden. Welcher Schritt muss zuerst erfolgen?
Lösung: Der Nachfolger von X wird auf B gesetzt. — Zuerst wird der neue Knoten mit dem bisherigen Rest verbunden: X → B. Danach darf A auf X zeigen.
Wie funktionieren Suchen und Löschen?

Beim Suchen beginnst du am Kopf. Du vergleichst nacheinander die Nutzdaten jedes erreichbaren Knotens mit dem gesuchten Wert. Die Suche endet bei einem Treffer oder bei NULL.

Um in 7 → 5 → 4 → NULL den Knoten 5 zu löschen, brauchst du bei einfacher Verkettung seinen Vorgänger 7.

Beispiel

Der Nachfolger von 7 wird nicht mehr auf 5, sondern direkt auf den Nachfolger von 5 gesetzt. Dieser ist 4.

Vorher: 7 → 5 → 4 → NULL

Nachher: 7 → 4 → NULL

Der Knoten 5 ist nun vom Kopf aus nicht mehr erreichbar.

Das Löschen des ersten Knotens ist ein Randfall: Es gibt keinen vorherigen Datenknoten. Stattdessen wird der Kopf auf den zweiten Knoten gesetzt. War nur ein Knoten vorhanden, zeigt der Kopf danach auf NULL.

Lückentext

Wähle in jeder Lücke die passende Form und prüfe anschließend deine Antworten.

Beim Suchen beginnt der Durchlauf am . Zum Löschen eines mittleren Knotens wird sein mit dem Nachfolger verbunden. Beim Löschen des ersten Knotens muss der angepasst werden.

Lösungen: Lücke 1: Kopf; Lücke 2: Vorgänger; Lücke 3: Kopf. Entscheidend ist die Erreichbarkeit: Der Kopf eröffnet den Listenweg, und beim Löschen wird der Zielknoten auf diesem Weg überbrückt.
Welche Laufzeiten gelten wirklich?

Die Schreibweise O(1) bedeutet, dass die Zahl der nötigen Schritte nicht mit der Listenlänge wächst. O(n) bedeutet, dass im ungünstigsten Fall eine Zahl von Schritten nötig ist, die mit der Anzahl n der Elemente wächst.

Für eine einfach verkettete Liste gelten wichtige Bedingungen:

  • Einfügen am Anfang: O(1).
  • Einfügen hinter einem bereits bekannten Knoten: O(1) für die Verweisänderungen.
  • Suchen eines Wertes: im ungünstigsten Fall O(n).
  • Zugriff auf eine Position: O(n), weil die Liste vom Anfang durchlaufen werden muss.
  • Anhängen ohne gespeicherten Endezeiger: O(n), weil zuerst das Ende gesucht wird.
  • Anhängen mit aktuellem Endezeiger: O(1).
  • Löschen hinter einem bereits bekannten Vorgänger: O(1) für das Überbrücken.
Gut zu wissen

Die Aussage „Einfügen und Löschen dauern O(1)“ ist nur dann vollständig, wenn der benötigte Vorgänger oder Einfügepunkt schon bekannt ist. Muss er zuerst gesucht werden, kann der gesamte Vorgang O(n) dauern.

Teste dich
Frage 1 von 2MittelEine Liste besitzt nur einen Kopfzeiger. Ein neuer Wert soll ans Ende einer Liste mit n Knoten. Welche Laufzeit hat der gesamte Vorgang im ungünstigsten Fall?
Lösung: O(n), weil das Ende zuerst durchlaufen werden muss — Ohne Endezeiger wird vom Kopf bis zum letzten Knoten gelaufen. Das Anhängen selbst ist konstant, der gesamte Vorgang aber linear.
Frage 2 von 2SchwerEin Algorithmus besitzt bereits eine Referenz auf den Vorgänger der Löschposition. Was folgt daraus?
Lösung: Das lokale Überbrücken benötigt O(1). — Bei bekanntem Vorgänger genügt eine konstante Zahl von Verweisänderungen; andere Knoten werden nicht verschoben.
Welche Varianten gibt es?

Bei einer doppelt verketteten Liste enthält jeder Datenknoten einen Nachfolger- und einen Vorgängerverweis. Du kannst die Liste deshalb vorwärts und rückwärts durchlaufen.

Liegt bereits eine Referenz auf einen zu löschenden mittleren Knoten vor, sind auch seine beiden Nachbarn unmittelbar erreichbar. Diese können direkt miteinander verbunden werden. Dafür benötigt jeder Knoten zusätzlichen Speicher, und beim Verändern müssen mehr Verweise konsistent bleiben.

Bei einer kreisförmig verketteten Liste verweist der letzte Knoten wieder auf den ersten. NULL markiert dann nicht das Ende. Ein festgelegter Kopf oder Wächter ist nötig, damit der Anfang und das Ende eines vollständigen Durchlaufs erkennbar bleiben.

Ein Wächterknoten enthält keine normalen Nutzdaten. Er kann Randfälle vereinheitlichen, etwa das Einfügen oder Löschen am Anfang. Algorithmen müssen ihn jedoch ausdrücklich von Datenknoten unterscheiden.

Merke

Eine gültige doppelt verkettete Liste muss in beide Richtungen zusammenpassen: Zeigt A vorwärts auf B, muss B rückwärts auf A zeigen.

Teste dich
Frage 1 von 1MittelEin bekannter mittlerer Knoten wird aus einer doppelt verketteten Liste gelöscht. Was muss danach gelten?
Lösung: Sein Vorgänger und sein Nachfolger verweisen passend aufeinander. — Doppelte Verkettung verlangt konsistente Beziehungen in beiden Richtungen. Beide Nachbarknoten müssen deshalb angepasst werden.
Wann passt eine Liste besser als ein Array?

Ein Array bietet direkten Zugriff über einen Index. Ein Element an einer bekannten Position ist deshalb in O(1) erreichbar. Beim Einfügen oder Löschen in der Mitte müssen jedoch möglicherweise viele Elemente verschoben werden.

Eine verkettete Liste verschiebt keine Nutzdaten. Sie passt besonders dann, wenn die Elementzahl veränderlich ist und häufig an bereits bekannten Stellen eingefügt oder gelöscht wird. Für häufige Zugriffe wie „Gib mir Element 800“ ist sie meist ungeeignet, weil der Weg am Kopf beginnt.

AnforderungHäufig passende StrukturBegründung
häufiger Zugriff über einen IndexArraydirekter Zugriff in O(1)
häufiges Einfügen hinter einem bekannten Knotenverkettete Listelokale Verweisänderung in O(1)
häufige Vorwärts- und Rückwärtsläufedoppelt verkettete Listebeide Richtungen sind gespeichert
dynamische Folge mit schnellem AnhängenListe mit Endezeigerletzter Knoten ist direkt bekannt

Die Begriffe Liste und verkettete Liste sind nicht immer gleichbedeutend: Eine Liste kann als abstrakter Datentyp durch ihre erlaubten Operationen beschrieben werden. Eine konkrete Bibliothek kann diese Operationen intern durch ein Array oder durch verkettete Knoten umsetzen.

Teste dich
Frage 1 von 1SchwerEine Anwendung liest sehr oft das Element an einem beliebigen Index, fügt aber nur selten etwas ein. Welche Wahl ist besser begründet?
Lösung: Ein Array, weil der Indexzugriff direkt erfolgt — Für häufigen wahlfreien Indexzugriff ist ein Array passend. Zusätzliche Verweise einer Liste ersetzen keinen direkten Indexzugriff.
Karteikasten
Karteikasten

Überlege zuerst selbst und drehe die Karte anschließend zum Prüfen um.

Alles auf einen Blick
Mindmap
  • Verkettete Liste
    • Aufbau
      • Kopf
      • Knoten mit Nutzdaten und Verweis
      • Listenende oder Kreisverbindung
    • Operationen
      • Suchen durch schrittweises Durchlaufen
      • Einfügen durch sichere Verweisreihenfolge
      • Löschen durch Überbrücken
    • Varianten
      • einfach verkettet
      • doppelt verkettet
      • kreisförmig verkettet
    • Auswahl
      • dynamisches Wachstum
      • kein direkter Indexzugriff
      • Laufzeit hängt von bekannten Referenzen ab
Abschluss-Check
Teste dich
Frage 1 von 3LeichtWas kennzeichnet eine einfach verkettete Liste?
Lösung: Jeder Knoten besitzt einen Verweis auf seinen Nachfolger. — Nutzdaten und Nachfolgerverweis bilden den Knoten einer einfach verketteten Liste.
Frage 2 von 3MittelIn P → Q → R soll Q gelöscht werden. Welche Änderung ist nötig, wenn P bekannt ist?
Lösung: Der Nachfolger von P wird auf R gesetzt. — Q wird überbrückt. Danach führt der erreichbare Listenweg direkt von P zu R.
Frage 3 von 3SchwerEine Funktion sucht zuerst den Vorgänger einer Position und fügt danach einen Knoten ein. Welche Aussage beschreibt den Gesamtaufwand im ungünstigsten Fall korrekt?
Lösung: Die Suche kann O(n) dauern, obwohl die anschließende Verweisänderung O(1) benötigt. — Trenne Positionssuche und lokale Änderung. Erst diese Unterscheidung macht die Laufzeitangabe vollständig.

Wenn du alle drei Abschlussfragen begründen kannst, verstehst du nicht nur den Aufbau der Liste, sondern auch die entscheidenden Bedingungen hinter ihren Laufzeiten.

Passend dazu