Einfach verkettete Listen in C
Einfach verkettete Listen oder linked lists sind eine fundamentale Datenstruktur, die ich hier anhand von Code-Beispielen und Grafiken erklären will.
Einfach verkettete Listen zeichnen sich dadurch aus, dass man besonders einfach Elemente einfügen kann, wodurch sie sich besonders gut für Insertion Sort eignen. Eine Verallgemeinerung stellen die doppelt verketteten Listen da.
Knoten
Eine einfach verkettete Liste besteht aus Knoten, Englisch nodes, die einen Zeiger auf das nächste Element und auf Daten.
struct list_node { int data; struct list_node *next; };
Um nicht jedes mal das struct
mitschleppen zu müssen, kann
man eine Abkürzung definieren:
typedef struct list_node* node;
Eine leere Liste besteht aus einem Kopf (Head) und nichts sonst:
- Eine leere Liste
Wenn man mehrere Elemente einfügt, sieht das so aus:
- Eine einfach verkettete Liste mit einem Kopf und zwei Knoten.
Elemente Einfügen
Wenn man einen Zeiger auf ein Element der Liste hat, ist es einfach, ein Element dahinter einzufügen.
Dazu muss man den next
-Zeiger der Liste auf das neue
Element setzen, und den next
-Zeiger des neuen Element auf
den alten Wert des next
-Zeigers der Liste:
node insert_right(node list, int data){ node new_node = (node) malloc(sizeof(struct list_node)); new_node->data = data; new_node->next = list->next; list->next = new_node; return new_node; }
-
In diese List soll links neben
node1
ein Element mit dem Datum3
eingefügt werden. - Durch das Setzen eines Zeigers wird das neue Element in die Liste eingegliedert.
- Die gleiche Liste in etwas schönerer Darstellung
Elemente löschen
Auch das Löschen eines Elements ist einfach, wenn man einen Zeiger auf das Element links des zu löschenden Elements hat.
Dazu muss man nur den next
-Zeiger des linken Elements
auf das Element rechts des zu löschenden setzen:
node delete_right(node list){
node tmp = list->next;
list->next = list->next->next;
free(tmp);
return list;
}
In diesem Fall wurde noch ein temporärer Zeiger benutzt, um den Speicher des genutzten Elements freizugeben.
- Aus dieser Liste soll das erste Element gelöscht werden.
- Und schon ist es gelöscht.
Insertion Sort mit verketteten Listen
Eine schöne Anwendung für einfach verkettete Listen ist der Sortieralgorithmus "Insertion Sort", oder auf Deutsch "Sortieren durch einfügen".
Für große Datenmengen eignet sich Insertion Sort nicht, weil die Laufzeit quadratisch mit der Anzahl der Elemente wächst, aber für kleine Datenmengen (vielleicht bis 20 Elemente) es schneller als die "schnellen" Algorithmen wie Mergesort oder Quicksort.
Es ist auch ganz einfach: man startet mit einer leeren Liste, und wenn man Elemente einfügt, achtet man darauf, sie an der richtigen Stelle einzufügen:
node insertion_sort(int *a, int count){ node list = new_list(); node c; int i; for (i = 0; i < count; i++){ c = list; while(c->next != NULL &&; c->next->data < a[i]){ c = c->next; } insert_right(c, a[i]); } return list; }
In Worten: mache für jedes Element des zu sortierenden Arrays das folgende:
Gehe solange vom Kopf der Liste nach rechts, bis das Ende erreicht ist oder das nächste Element größer als das einzufügende ist, und füge dann das Element davor ein.
Suche
Um ein Element in der Liste zu suchen, hangelt man sich von einem
Listenelement zum nächsten, entweder bis man die gesuchte Element gefunden
hat, oder bis man NULL
erreicht:
node search_for(node list, int data) { while (list != NULL) { if (list->data == data) return list; list = list->next; } return NULL; }
Wenn man erst mal den node
pointer hat, kann man z.B. rechts
davon einfügen oder löschen.
Zusammenfassung
Eine einfach verkettete Liste speichert pro Element einen Zeiger auf das nächste Element und die Nutzdaten. Das Durchlaufen von Rechts nach Links, das Einfügen und das Entfernen des Elements rechts des aktuellen Elements sind einfach und erfordern nur das umsetzen von zwei Zeigern.
Gegenüber doppelt verketteten Listen brauchen sie also weniger Verwaltungsaufwand, bei etwas geringerer Flexibilität.
Weiteres Lesematerial
- doppelt verkettete Listen
- Heaps und Heapsort
- Überlegte Verwendung von Datentypen und Datenstrukturen
Bücher
"Algorithmen in C" von Robert Sedgewik ist allgemeinverständlich und praktisch. "The Art of Computer Programming" von Donald Knuth ist ein Klassiker, und beschreibt für den mathematisch interessierten Leser Algorithmen, Datenstrukturen und ihre Vor- und Nachteile im Detail (Englisch).