Menu
Coddy logo textTech

Doppelt verkettete Liste

Zuletzt aktualisiert

Eine doppelt verkettete Liste ist eine verkettete Liste, bei der jeder Knoten zwei Zeiger hält: next (zum folgenden Knoten) und prev (zum vorhergehenden). Dieser zusätzliche Rückwärtsverweis erlaubt es, in beide Richtungen zu traversieren und einen Knoten in O(1) zu löschen, wenn man bereits eine Referenz auf ihn hat, weil man seinen Vorgänger direkt erreichen kann, statt vom Kopf aus zu laufen. Drücke oben auf Wiedergabe, um zu sehen, wie Knoten in beide Richtungen verknüpft und neu verknüpft werden.

Der Preis ist ein zusätzlicher Zeiger pro Knoten und mehr Verwaltungsaufwand: Jedes Einfügen und Löschen muss sowohl next als auch prev bei den Nachbarn aktualisieren. Es ist die Struktur hinter vielen Deques und LRU-Caches, wo schnelles Entfernen an beiden Enden zählt.

Zeitkomplexität

OperationKomplexitätAnmerkungen
Einfügen am Kopf/EndeO(1)Mit Kopf- und Endzeigern
Bekannten Knoten löschenO(1)Erreicht prev direkt, kein Durchlaufen
SucheO(n)Weiterhin linearer Scan
Zugriff über IndexO(n)Kein wahlfreier Zugriff

Einfach vs. doppelt verkettete Liste

AspektEinfachDoppelt
Zeiger pro Knoten1 (next)2 (next + prev)
Rückwärts traversierenNeinJa
Bekannten Knoten löschenO(n) (prev suchen)O(1)
SpeicheraufwandGeringerHöher

Durchgerechnetes Beispiel

Aufbau von [10, 20, 30] durch Anhängen, dann Löschen von Knoten 20:

SchrittStrukturAktion
StartnullLeere Liste: head und tail sind beide null
10 anhängen10Erster Knoten; head und tail zeigen darauf, prev = next = null
20 anhängen10 <-> 20Setze 10.next = 20 und 20.prev = 10; tail = 20
30 anhängen10 <-> 20 <-> 30Setze 20.next = 30 und 30.prev = 20; tail = 30
20 löschen10 <-> 30Mit 20.prev und 20.next: setze 10.next = 30 und 30.prev = 10 in O(1)

Wann eine doppelt verkettete Liste verwenden

Verwenden, wennVermeiden, wenn
Du in beide Richtungen traversieren oder einfügen musstDu dich nur vorwärts bewegst: eine einfache Liste ist leichter
Du beliebige Knoten löschst, auf die du bereits eine Referenz hältst (O(1))Du meist über Position indizierst: nutze ein Array für O(1)-Zugriff
Du einen Deque, LRU-Cache oder Rückgängig-Verlauf implementierstDer Speicher knapp ist: der zusätzliche prev-Zeiger verdoppelt den Verknüpfungsaufwand
Einfügungen und Entfernungen häufig an beiden Enden geschehenDie Daten klein sind und sich selten ändern: Array-Kopien sind günstiger

Doubly Linked List-Code

Eine saubere, lauffähige Doubly Linked List-Implementierung in Python, JavaScript, Java, C++, C. Wähle eine Sprache, kopiere den Code oder öffne ihn vorgeladen im Coddy-Playground.

Doubly Linked List-Code in Python

Python
1class Node:2    def __init__(self, value):3        self.value = value4        self.prev = None5        self.next = None6
7
8class DoublyLinkedList:9    def __init__(self):10        self.head = None11        self.tail = None12
13    def append(self, value):14        node = Node(value)15        if self.tail is None:16            self.head = self.tail = node17            return18        # Wire both directions: old tail <-> new node19        node.prev = self.tail20        self.tail.next = node21        self.tail = node22
23    def prepend(self, value):24        node = Node(value)25        if self.head is None:26            self.head = self.tail = node27            return28        node.next = self.head29        self.head.prev = node30        self.head = node31
32    def forward(self):33        values, current = [], self.head34        while current:35            values.append(current.value)36            current = current.next37        return values38
39    def backward(self):40        values, current = [], self.tail41        while current:42            values.append(current.value)43            current = current.prev44        return values45
46
47lst = DoublyLinkedList()48for value in [2, 3, 4]:49    lst.append(value)50lst.prepend(1)51
52print("Forward: ", lst.forward())53print("Backward:", lst.backward())
Führe diesen Code im Python-Playground aus

FAQ zu doppelt verketteten Listen

Was ist der Unterschied zwischen einer einfach und einer doppelt verketteten Liste?
Eine einfach verkettete Liste hat einen Zeiger pro Knoten (next), sodass du dich nur vorwärts bewegen kannst. Eine doppelt verkettete Liste fügt einen prev-Zeiger hinzu, was Rückwärtstraversierung und das Löschen eines Knotens, auf den du eine Referenz hältst, in O(1) ermöglicht, um den Preis eines zusätzlichen Zeigers pro Knoten und der Aktualisierung zweier Verknüpfungen bei jeder Änderung.
Wann lohnt sich der zusätzliche Speicher einer doppelt verketteten Liste?
Wenn du Rückwärtstraversierung oder das Löschen beliebiger, bereits referenzierter Knoten in O(1) brauchst - klassische Fälle sind Deques (doppelendige Warteschlangen) und LRU-Caches, in denen Einträge häufig an beiden Enden verschoben und verdrängt werden.
Warum kann eine doppelt verkettete Liste einen Knoten in O(1) löschen?
Um einen Knoten zu entfernen, musst du seinen Vorgänger mit seinem Nachfolger verbinden. In einer einfach verketteten Liste müsstest du vom Kopf aus laufen, um den Vorgänger zu finden (O(n)); in einer doppelt verketteten Liste liefert der prev-Zeiger des Knotens den Vorgänger direkt, sodass das Neuverknüpfen O(1) ist.
Doppelt verkettete Liste oder Array: was sollte ich verwenden?
Verwende ein Array, wenn du O(1)-Zugriff über Index und cachefreundliche Iteration brauchst und Einfügungen meist am Ende erfolgen. Verwende eine doppelt verkettete Liste, wenn du bei vorhandener Knotenreferenz häufig in der Mitte oder an beiden Enden einfügst oder entfernst, da das O(1) gegenüber dem O(n)-Verschieben eines Arrays ist. Arrays gewinnen bei Speicher und Lokalität; die Liste gewinnt bei strukturellen Änderungen.
Was ist ein Wächterknoten (Sentinel) in einer doppelt verketteten Liste?
Ein Wächter- oder Dummy-Knoten ist ein Platzhalter vor dem Kopf und/oder nach dem Ende, sodass die Liste nie wirklich leer ist. Er beseitigt die null-Prüfungen für head, tail und Rand-Einfügungen/-Löschungen und lässt jede Operation demselben Neuverknüpfungspfad folgen. Viele produktive LRU-Cache-Implementierungen nutzen zwei Wächter, um die Enden nicht als Sonderfälle behandeln zu müssen.
Was ist der häufigste Fehler beim Löschen aus einer doppelt verketteten Liste?
Zu vergessen, head oder tail zu aktualisieren, wenn du den ersten oder letzten Knoten löschst, was einen hängenden Zeiger auf einen freigegebenen Knoten hinterlässt. Prüfe immer, ob node.prev gleich null ist (head aktualisieren) oder ob node.next gleich null ist (tail aktualisieren), bevor du die Nachbarn neu verdrahtest.
Coddy programming languages illustration

Meistere Algorithmen mit Coddy

LOS GEHT'S