Doppelt verkettete Liste: C++, Python (Code Beispiel)

Was ist eine doppelt verkettete Liste?

In einer doppelt verknรผpften Liste verfรผgt jeder Knoten รผber Links sowohl zum vorherigen als auch zum nรคchsten Knoten. Jeder Knoten besteht aus drei Elementen: eines enthรคlt die Daten und zwei weitere sind die Zeiger des nรคchsten und des vorherigen Knotens. Diese beiden Zeiger helfen uns, von einem bestimmten Knoten aus vorwรคrts oder rรผckwรคrts zu gehen.

Hier ist die Grundstruktur der doppelt verknรผpften Liste.

Struktur einer doppelt verknรผpften Liste
Struktur einer doppelt verknรผpften Liste

Jede verknรผpfte Liste hat einen Kopf- und einen Endknoten. Der Kopfknoten hat keinen โ€žvorherigenโ€œ Knoten (vorheriger Zeiger) und der Endknoten hat keinen โ€žnรคchstenโ€œ Knoten.

Hier sind einige wichtige Begriffe fรผr eine doppelt verkettete Liste:

  • Zurรผck: Jeder Knoten ist mit seinem vorherigen Knoten verknรผpft. Es wird als Zeiger oder Link verwendet.
  • Nรคchster: Jeder Knoten ist mit seinem nรคchsten Knoten verknรผpft. Es wird als Zeiger oder Link verwendet.
  • Datum: Dies wird verwendet, um Daten in einem Knoten zu speichern. โ€žDatenโ€œ kรถnnen andere enthalten Datenstrukturen im Inneren. Beispielsweise kรถnnen Zeichenfolgen, Wรถrterbรผcher, Sรคtze, Hashmaps usw. in den โ€žDatenโ€œ gespeichert werden.

Hier ist die Grundstruktur eines einzelnen Knotens in der doppelt verknรผpften Liste:

Struktur eines Knotens in einer doppelt verknรผpften Liste

Struktur eines Knotens in einer doppelt verknรผpften Liste

Operationen der doppelt verknรผpften Liste

Zu den Operationen einer doppelt verketteten Liste gehรถren das Hinzufรผgen und Lรถschen von Knoten, das Einfรผgen und Entfernen von Knoten sowie das Durchlaufen der verketteten Liste von oben nach unten.

Hier ist die Liste der Operationen, die wir mit der doppelt verketteten Liste implementieren kรถnnen:

  • Einschub vorne
  • Einfรผgung in den Schwanz oder letzten Knoten
  • Einfรผgung nach einem Knoten
  • Einfรผgung vor einem Knoten
  • Lรถschung von vorne
  • Lรถschung vom Schwanz
  • Suchen und lรถschen Sie einen Knoten
  • Von Kopf bis Schwanz queren
  • Schwanz zum Kopf kreuzen

Wir werden uns die Implementierung und den Pseudocode fรผr alle oben genannten Operationen ansehen.

Einfรผgung vor der doppelt verknรผpften Liste

Das Einfรผgen vorn bedeutet, dass wir einen Knoten in der verknรผpften Liste erstellen und ihn am Anfang der verknรผpften Liste platzieren mรผssen.

Beispielsweise gibt es einen gegebenen Knoten โ€ž15โ€œ. Wir mรผssen dies zum Hauptknoten hinzufรผgen.

Fรผr diesen Vorgang sind zwei wichtige Bedingungen zu beachten:

  1. Der neue Knoten ist der Hauptknoten, wenn in der doppelt verknรผpften Liste kein Knoten vorhanden ist.
  2. Wenn bereits ein Kopfknoten vorhanden ist, wird der vorherige Kopfknoten durch den neuen Knoten ersetzt.

Hier ist der Pseudocode fรผr diese Operation:

function insertAtFront (ListHead, value):
  newNode = Node()
  newNode.value = value
  ListHead.prev = NewNode
  NewNode.next = ListHead
  newNode.prev = NULL
  return ListHead
Einfรผgung in den Frontknoten
Einfรผgung in den vorderen Knoten

Einfรผgung am Ende der doppelt verknรผpften Liste

โ€žEinfรผgung am Endeโ€œ bedeutet, dass wir einen Knoten in der verknรผpften Liste erstellen und ihn am Ende platzieren.

Um dies durchzufรผhren, kรถnnen wir zwei Methoden verwenden:

  • Methode 1: Beginnen Sie mit dem Durchlaufen vom Kopf der doppelt verknรผpften Liste, bis das โ€žnรคchsteโ€œ null wird. Verknรผpfen Sie dann den neuen Knoten mit dem โ€žnรคchstenโ€œ.
  • Methode 2: Nehmen Sie den letzten Knoten der doppelt verknรผpften Liste. Dann wird der โ€žnรคchsteโ€œ Knoten des letzten Knotens mit dem neuen Knoten verknรผpft. Jetzt wird der neue Knoten der Endknoten sein.

Hier ist der Pseudocode zum Einfรผgen am Endknoten:

function insertAtTail(ListHead, value):
  newNode = Node()
  newNode.value = value
  newNode.next = NULL
  while ListHead.next is not NULL:
	then ListHead = ListHead.next
  newNode.prev = ListHead
  ListHead.next = newNode
  return ListHead
Einfรผgung am Ende der verknรผpften Liste

Einfรผgung am Ende der verknรผpften Liste

Einfรผgung nach einem Knoten

Nehmen wir an, wir haben eine vorhandene doppelt verkettete Liste wie die folgende:

Einfรผgen nach einem Knoten

Wir mรถchten einen bestimmten Knoten einfรผgen, der nach dem Knoten mit dem Wert โ€ž12โ€œ verknรผpft werden soll.

Hier sind die Schritte dafรผr:

Schritt 1) Vom Kopf zum letzten Knoten durchlaufen. รœberprรผfen Sie, welcher Knoten den Wert โ€ž12โ€œ hat.

Schritt 2) Erstellen Sie einen neuen Knoten und weisen Sie ihn als nรคchsten Zeiger des Knotens โ€ž12โ€œ zu. Der โ€žnรคchsteโ€œ Knoten des neuen Knotens wird 15 sein.

Hier ist der Pseudocode zum Einfรผgen eines Knotens nach einem Knoten in einer doppelt verknรผpften Liste:

function insertAfter(ListHead, searchItem, value):
  List = ListHead
  NewNode = Node()
  NewNode.value = value
  while List.value is not equal searchItem
	then List = ListHead.next
  List = List.next
  NewNode.next = List.next
  NewNode.prev = List
  List.next = NewNode
Einfรผgen nach einem Knoten

Einfรผgen nach einem Knoten

Einfรผgung vor einem Knoten

Dieser Vorgang รคhnelt eher dem โ€žEinfรผgen nach einem Knotenโ€œ. Dazu mรผssen wir nach dem Wert eines bestimmten Knotens suchen. Dann erstellen wir einen neuen Knoten und fรผgen ihn vor dem gesuchten Knoten ein.

Nehmen wir an, wir mรถchten einen bestimmten Knoten โ€ž15โ€œ vor dem Knoten โ€ž12โ€œ einfรผgen. Dann sind hier die Schritte dazu:

Schritt 1) Durchlaufen Sie die verknรผpfte Liste vom Kopfknoten zum Endknoten.

Schritt 2) รœberprรผfen Sie, ob der nรคchste Zeiger des aktuellen Knotens den Wert โ€ž12โ€œ hat oder nicht.

Schritt 3) Fรผgen Sie den neuen Knoten als โ€žnรคchstenโ€œ Knoten des aktuellen Knotens ein.

Hier ist der Pseudocode zum Einfรผgen eines Knotens vor einem Knoten in einer doppelt verknรผpften Liste:

function insertBefore(ListHead, searchItem, value):
  List = ListHead
  NewNode = Node()
  NewNode.value = value
  while List.next.value is not equal searchItem
	then List = ListHead.next
  NewNode.next = List.next
  NewNode.prev = List
  List.next = NewNode
Einfรผgen eines Knotens vor einem Knoten

Einfรผgen eines Knotens vor einem Knoten

Lรถschen Sie den Kopf der doppelt verknรผpften Liste

Der Hauptknoten in der doppelt verknรผpften Liste, der keinen vorherigen Knoten hat. Der nรคchste Zeiger ist also der neue Kopfknoten, wenn wir den Kopfknoten lรถschen mรถchten. Wir mรผssen auch den von einem Knoten belegten Speicher freigeben, wรคhrend wir einen Knoten lรถschen.

Hier sind die Schritte zum Lรถschen des Hauptknotens:

Schritt 1) Weisen Sie dem aktuellen Hauptknoten eine Variable zu.

Schritt 2) Besuchen Sie den โ€žnรคchstenโ€œ Knoten des aktuellen Hauptknotens und machen Sie den โ€žvorherigenโ€œ Knoten (vorheriger Zeiger) zu โ€žNULLโ€œ. Das bedeutet, dass wir den zweiten Knoten vom ersten Knoten trennen.

Schritt 3) Geben Sie den vom vorherigen Hauptknoten belegten Speicher frei.

Hier ist der Pseudocode zum Lรถschen des Kopfes aus einer doppelt verknรผpften Liste:

function deleteHead(ListHead):
  PrevHead = ListHead
  ListHead = ListHead.next
  ListHead.prev = NULL
  PrevHead.next = NULL
  free memory(PrevHead)
  return ListHead
Lรถschen des Hauptknotens

Lรถschen des Hauptknotens

Nach jedem Lรถschvorgang muss der zugewiesene Speicher gelรถscht werden. Andernfalls bleibt der Speicher fรผr den gelรถschten Block wรคhrend der gesamten Laufzeit des Programms belegt. Keine andere Anwendung kann diesen Speicherabschnitt verwenden.

Lรถschen Sie das Ende der doppelt verknรผpften Liste.

Dieser Vorgang ist รคhnlich wie das Lรถschen des Kopfes. Hier mรผssen wir anstelle des Kopfes das Ende lรถschen. Um einen Knoten als Endeknoten zu identifizieren, sollten wir prรผfen, ob der nรคchste Zeiger oder der nรคchste Knoten null ist oder nicht. Nachdem wir das Ende gelรถscht haben, mรผssen wir den Speicher freigeben.

Dieser Vorgang wird auch als โ€žLรถschung von der Rรผckseiteโ€œ bezeichnet.

Hier sind die Schritte dazu:

Schritt 1) Durchlaufen Sie bis zum Endknoten der doppelt verknรผpften Liste.

Schritt 2) Weisen Sie dem Endknoten eine Variable oder einen Zeiger zu.

Schritt 3) Machen Sie den โ€žnรคchstenโ€œ Knoten zu NULL und geben Sie den Speicher des Endknotens frei.

Hier ist der Pseudocode zum Lรถschen des Endknotens:

function DeleteTail( ListHead ):
  head = ListHead
  while ListHead.next is not NULL:
	ListHead = ListHead.next
  Tail = ListHead.next
  ListHead.next = NULL
  free memory( Tail )
  return head

Lรถschen Sie den Schwanz der doppelten Verknรผpfung

Suchen und lรถschen Sie einen Knoten aus der doppelt verknรผpften Liste

Mit diesem Vorgang kรถnnen wir nach bestimmten Knotendaten suchen und diesen Knoten lรถschen. Wir mรผssen eine lineare Suche durchfรผhren, da die verknรผpfte Liste eine lineare Datenstruktur ist. Nach dem Lรถschen mรผssen wir auch den Speicher freigeben.

Hier sind die Schritte zum Suchen und Lรถschen eines Knotens in der doppelt verknรผpften Liste:

Schritt 1) Durchlaufen Sie die verknรผpfte Liste vom Kopf bis der Wert des Knotens dem Suchelement entspricht.

Schritt 2) Weisen Sie dem รผbereinstimmenden Knoten eine Variable โ€ždeleteNodeโ€œ zu.

Schritt 3) Weisen Sie den vorherigen Knoten des โ€ždeleteNodeโ€œ dem nรคchsten Knoten zu.

Schritt 4) Den Speicher des โ€ždeleteNodeโ€œ freigeben

Hier ist der Pseudocode zum Suchen und Lรถschen eines Knotens aus einer verknรผpften Liste:

function SearchAndDelete(ListHead, searchItem):
  head = ListHead
  while ListHead.next.value not equals searchItem:
	head = head.next
  deleteNode = head.next
  head.next = head.next.next
  head.next.prev = head
  deleteNode.next, deleteNode.next = NULL
  free memory(deleteNode)
  return ListHead
Suchen und lรถschen OperaProduktion

Such- und Lรถschvorgang

Durchlaufen Sie eine doppelt verknรผpfte Liste von vorne

Vom Kopfknoten aus durchlaufen und รผber den nรคchsten Knoten iterieren, bis wir โ€žNULLโ€œ finden. Wรคhrend wir jeden Knoten durchlaufen, kรถnnen wir den Wert des Knotens drucken. Hier sind die Schritte zum Queren von vorne (Vorwรคrtsrichtung):

Schritt 1) Weisen Sie dem aktuellen Hauptknoten einen Zeiger oder eine Variable zu.

Schritt 2) Iterieren Sie zum nรคchsten Knoten des Kopfes, bis Sie โ€žNULLโ€œ erhalten.

Schritt 3) Drucken Sie die Daten des Knotens in jeder Iteration.

Schritt 4) Geben Sie den Hauptknoten zurรผck.

Hier ist der Pseudocode zum Durchlaufen einer doppelt verknรผpften Liste von vorne:

function traverseFromFront(ListHead):
  head = ListHead
  while head not equals to NULL:
	print head.data
	head = head.next
  return ListHead

Hier ist die Rรผckgabe nicht zwingend erforderlich. Es empfiehlt sich jedoch, den Kopfknoten nach den Vorgรคngen zurรผckzugeben.

Durchlaufen Sie eine doppelt verknรผpfte Liste von hinten

Dieser Vorgang ist das Gegenteil der Traverse von vorne. Der Ansatz ist der gleiche, mit einem kleinen Unterschied. Wir mรผssen zum Endknoten und dann vom Endknoten zum vorderen Knoten traversieren.

Hier sind die Schritte zum Durchlaufen einer doppelt verknรผpften Liste von hinten:

Schritt 1) Durchqueren Sie, bis wir den Endknoten erreichen.

Schritt 2) Vom Endknoten aus werden wir durchlaufen, bis wir den vorherigen Knoten als โ€žNULLโ€œ erhalten. Der โ€žprevโ€œ (vorheriger Zeiger) ist fรผr den Kopfknoten null

Schritt 3) Bei jeder Iteration drucken wir die Knotendaten.

Hier ist der Pseudocode fรผr die Durchquerung von hinten:

function traverseFromBack(ListHead):
  head = ListHead
  while head not equals NULL:
	head = head.next
  tail = head
  while tail not equal to NULL:
	print tail.value
	tail = tail.prev
  return ListHead

Unterschied zwischen einfach und doppelt verknรผpfter Liste

Der Hauptunterschied zwischen der Single- und der Double Linked-Liste besteht in der Anzahl der Links.

Unterschied zwischen einfach und doppelt verknรผpfter Liste

Hier ist der Unterschied zwischen den Knoten einer einfach verknรผpften Liste und der Knotenstruktur der doppelt verknรผpften Liste:

Feld Einfach verknรผpfte Liste Doppelt verknรผpfte Liste
Struktur Einfach verknรผpfte Liste hat ein Datenfeld und einen Link zum nรคchsten Knoten. Eine doppelt verknรผpfte Liste verfรผgt รผber ein Datenfeld und zwei Links. Eine fรผr den vorherigen Knoten und eine fรผr den nรคchsten Knoten.
Traversal Es kann nur von Kopf bis Schwanz wandern. Es kann sowohl vorwรคrts als auch rรผckwรคrts fahren.
Memory Belegt weniger Speicher. Sie belegt mehr Speicher als eine einfach verknรผpfte Liste.
Barierrefreiheit Einfach verknรผpfte Listen sind weniger effizient, da sie nur einen Link zum nรคchsten Knoten verwenden. Fรผr den vorherigen Knoten gibt es keinen Link. Doppelt verknรผpfte Listen sind effizienter als einfach verknรผpfte Listen.

Doppelt verkettete Liste in C++

#include<iostream>
using namespace std;
  struct node{
  int data;
  struct node *next;
  struct node *prev;
  };
void insertFront(node* &listHead, int value){
  node* newNode = new node();
  newNode->data = value;
  newNode->prev = NULL;
  newNode->next = NULL;
  if(listHead!=NULL)
  {
	listHead->prev = newNode;
  	newNode->next = listHead;
  }
  
  listHead = newNode;
  cout<<"Added "<<value<<" at the front"<<endl;
  }
void insertEnd(node * &listHead, int value){
  if(listHead==NULL)
  {
  	insertFront(listHead,value);
  }
  node* newNode = new node();
  newNode->data = value;
  newNode->prev = NULL;
  newNode->next = NULL;
  node *head = listHead;
  while(head->next!=NULL){
  head = head->next;
  }
  head->next = newNode;
  newNode->prev = head;
  cout<<"Added "<<value<<" at the end"<<endl;
  }
void insertAfter(node * &listHead, int searchValue,int value){
  node* newNode = new node();
  newNode->data = value;
  newNode->prev = NULL;	
  newNode->next = NULL;
  node *head = listHead;	
  while(head->next!=NULL &&  head->data!=searchValue){	
  head = head->next;	
  }	
  newNode->next = head->next;	
  head->next = newNode;	
  newNode->prev = head;	
  if(newNode->next !=NULL){	
  newNode->next->prev = newNode;	
  }	
  cout<<"Inserted "<<value<<" after node "<<searchValue<<endl;
  }
void insertBefore(node * &listHead, int searchValue,int value){
  node* newNode = new node();
  newNode->data = value;
  newNode->prev = NULL;	
  newNode->next = NULL;	
  node *head = listHead;	
  while(head->next!=NULL &&  head->next->data!=searchValue){	
  head = head->next;	
  }	
  newNode->next = head->next;	
  head->next = newNode;	
  newNode->prev = head;	
  if(newNode->next !=NULL){	
  newNode->next->prev = newNode;	
  }	
  cout<<"Inserted "<<value<<" before node "<<searchValue<<endl;	
  }
void traverseFromFront(node *listHead){
  node* head = new node();
  head = listHead;
  cout<<"Traversal from head:\t";	
  while(head!=NULL){	
  cout<<head->data<<"\t ";	
  head = head->next;	
  }	
  cout<<endl;
  }	
void traverseFromEnd(node *listHead){
  node* head = new node();
  head = listHead;	
  cout<<"Traversal from head:\t";	
  while(head->next!=NULL){	
  head = head->next;	
  }	
  node *tail = head;	
  while(tail!=NULL){	
  cout<<tail->data<<"\t";	
  tail = tail->prev;	
  }	
  cout<<endl;	
  }
void searchAndDelete(node **listHead, int searchItem){
  node* head = new node();
  head = (*listHead);
  while(head->next!=NULL &&  head->data!=searchItem){
  head = head->next;
  }
  if(*listHead == NULL || head == NULL) return;
  if((*listHead)->data == head->data){
  	*listHead = head->next;
  }
  if(head->next != NULL){
  	head->next->prev = head->prev;
  }
  
  if(head->prev != NULL){
  	head->prev->next = head->next;
  }
  free(head);
  cout<<"Deleted Node\t"<<searchItem<<endl;
  return;
  }
int main(){
  node *head = NULL;
  insertFront(head,5);
  insertFront(head,6);
  insertFront(head,7);
  insertEnd(head,9);
  insertEnd(head,10);
  insertAfter(head,5,11);
  insertBefore(head,5,20);
  traverseFromFront(head);
  traverseFromEnd(head);
  searchAndDelete(&head,7);
  traverseFromFront(head);
  traverseFromEnd(head);
}

Ausgang

Added 5 at the front
Added 6 at the front
Added 7 at the front
Aded 9 at the end
Added 10 at the end
Inserted 11 after node 5
Inserted 20 before node 5
Traversal from head:    7        6       20      5       11      9       10
Traversal from head:    10      9       11      5       20      6       7
Deleted Node    7
Traversal from head:    6        20      5       11      9       10
Traversal from head:    10      9       11      5       20      6

Doppelt verkettete Liste in Python

class node:
  def __init__(self,data = None, prev=None, next = None):
    self.data = data
    self.next = next
    self.prev = prev
class DoublyLinkedList:
  def __init__(self):
    self.head = None

  def insertFront(self, val):
    newNode = node(data=val)
    newNode.next = self.head
    if self.head is not None:
      self.head.prev = newNode
    self.head = newNode
    print("Added {} at the front".format(val))

  def insertEnd(self,val):
    newNode = node(data=val)
    if self.head is None:
      self.insertFront(val)
    
    temp = self.head
    while temp.next is not None:
      temp = temp.next
    temp.next = newNode
    newNode.prev = temp
    print("Added {} at the end".format(val))

  def traverseFromFront(self):
    temp = self.head
    print("Traversing from head:\t",end="")
    while temp:
      print("{}\t".format(temp.data),end="")
      temp = temp.next
    print()

  def traverseFromEnd(self):
    temp = self.head
    print("Traversing from Tail:\t",end="")
    while temp.next is not None:
      temp = temp.next
    tail = temp
    while tail is not None:
      print("{}\t".format(tail.data),end="")
      tail = tail.prev
    print()
  
  def insertAfter(self,searchItem, value):
    newNode = node(data=value)

    temp = self.head
    while temp.next is not None and temp.data is not searchItem:
      temp = temp.next
    
    newNode.next = temp.next
    temp.next = newNode
    newNode.prev = temp

    if newNode.next is not None:
      newNode.next.prev = newNode
    print("Inserted {} after node {}".format(value,searchItem))

  def insertBefore(self,searchItem, value):
    newNode = node(data=value)

    temp = self.head
    while temp.next is not None and temp.next.data is not searchItem:
      temp = temp.next
    
    newNode.next = temp.next
    temp.next = newNode
    newNode.prev = temp

    if newNode.next is not None:
      newNode.next.prev = newNode
    print("Inserted {} before node {}".format(value,searchItem))

  def searchAndDelete(self,searchItem):
    temp = self.head

    while temp.next is not None and temp.data is not searchItem:
      temp = temp.next
    
    if self.head is None or temp is None:
      return

    if self.head.data is temp.data:
      self.head = temp.next

    if temp.next is not None:
      temp.next.prev = temp.prev
    
    if temp.prev is not None:
      temp.prev.next = temp.next
    
    print("Deleted Node\t{}".format(searchItem))
    return

doublyLinkedList = DoublyLinkedList()
doublyLinkedList.insertFront(5)
doublyLinkedList.insertFront(6)
doublyLinkedList.insertFront(7)
doublyLinkedList.insertEnd(9)
doublyLinkedList.insertEnd(10)
doublyLinkedList.insertAfter(5, 11)
doublyLinkedList.insertBefore(5, 20)
doublyLinkedList.traverseFromFront()
doublyLinkedList.traverseFromEnd()
doublyLinkedList.searchAndDelete(7)
doublyLinkedList.traverseFromFront()
doublyLinkedList.traverseFromEnd()

Ausgang

Added 5 at the front
Added 6 at the front
Added 7 at the front
Added 9 at the end
Added 10 at the end
Inserted 11 after node 5
Inserted 20 before node 5
Traversing from head:   7       6       20      5       11      9       10
Traversing from Tail:   10      9       11      5       20      6       7
Deleted Node    7
Traversing from head:   6       20      5       11      9       10
Traversing from Tail:   10      9       11      5       20      6

Komplexitรคt einer doppelt verketteten Liste

Im Allgemeinen wird die Zeitkomplexitรคt in drei Typen unterteilt.

Sie sind:

  1. besten Case
  2. Durchschnittlicher Fall
  3. Schlimmsten Fall

Zeitliche Komplexitรคt im besten Fall fรผr doppelt verkettete Listen:

  1. Das Einfรผgen in Kopf oder Ende kostet O(1). Weil wir die verknรผpfte Liste nicht durchlaufen mรผssen. Der Kopf- und der Endzeiger kรถnnen uns mit einer Zeitkomplexitรคt von O(1) Zugriff auf den Kopf- und Endknoten geben.
  2. Das Lรถschen am Anfang oder am Ende kostet O(1).
  3. Die Suche nach einem Knoten hat eine Zeitkomplexitรคt von O(1), da der Zielknoten der Kopfknoten sein kann.

Zeitliche Komplexitรคt im Durchschnittsfall fรผr doppelt verkettete Listen:

  1. Das Einfรผgen am Anfang oder Ende hat eine Zeitkomplexitรคt von O(1).
  2. Das Lรถschen am Anfang oder Ende hat eine Zeitkomplexitรคt von O(1).
  3. Die Suche nach einem Knoten hat eine Zeitkomplexitรคt von O(n). Denn das Suchelement kann sich an beliebiger Stelle in der verknรผpften Liste befinden. Dabei ist โ€žnโ€œ die Gesamtzahl der in der verknรผpften Liste vorhandenen Knoten.

Die Zeitkomplexitรคt der doppelt verketteten Liste im schlimmsten Fall ist die gleiche wie im Durchschnittsfall.

Speicherkomplexitรคt einer doppelt verknรผpften Liste

Die Speicherkomplexitรคt betrรคgt O(n), wobei โ€žnโ€œ die Gesamtzahl der Knoten ist. Wรคhrend der Implementierung der verknรผpften Liste mรผssen wir den von uns verwendeten Speicher freigeben. Andernfalls kommt es bei einer grรถรŸeren verknรผpften Liste zu Speicherverlusten.

Zusammenfassung

  • Eine verknรผpfte Liste ist eine Art lineare Datenstruktur, eine Sammlung von Daten, die linear dargestellt werden.
  • Eine doppelt verknรผpfte Liste ist eine Art verknรผpfter Liste, bei der ein Knoten Verknรผpfungen sowohl zum vorherigen als auch zum nรคchsten Knoten aufweist.
  • Eine doppelt verkettete Liste enthรคlt alle Operationen wie das Hinzufรผgen eines Knotens, das Lรถschen eines Knotens, das Einfรผgen eines Knotens nach oder vor einem anderen Knoten und das Durchlaufen der verketteten Liste von Anfang bis Ende.
  • Eine doppelt verknรผpfte Liste verfรผgt รผber ein Datenfeld und zwei Links. Eine fรผr den vorherigen Knoten und eine fรผr den nรคchsten Knoten.
  • Komplexitรคt einer doppelt verketteten Liste, bester Fall, durchschnittlicher Fall
  • Und im schlimmsten Fall.

Fassen Sie diesen Beitrag mit folgenden Worten zusammen: