Array vs. verkettete Liste: Zugriff, Einfügen und Löschen, Speicherlayout, Cache und Zeitkomplexität
Ein Array legt Elemente desselben Typs lückenlos hintereinander im Speicher ab, sodass sich die Position jedes Elements aus seinem Index berechnen und in konstanter Zeit lesen oder schreiben lässt. Eine verkettete Liste ist eine Datenstruktur, in der jedes Element einen Wert und einen Zeiger auf das nächste Element enthält und die Elemente durch das Verfolgen dieser Zeiger verbunden sind; sie können daher an getrennten Stellen im Speicher liegen. Ein Array liest schnell, doch Einfügen oder Löschen in der Mitte bedeutet, die dahinterliegenden Elemente zu verschieben. Eine verkettete Liste kann einfügen oder löschen, indem nur Zeiger geändert werden, sobald die Position bekannt ist, doch zum Lesen des i-ten Elements muss man sie vom Anfang an durchlaufen. Die Grundregel: ein Array, wenn meist per Index gelesen wird, und eine verkettete Liste, wenn oft an bekannten Positionen eingefügt oder gelöscht wird.
| Merkmal | Array | Verkettete Liste |
|---|---|---|
| Speicherlayout | Die Elemente liegen in einem zusammenhängenden Block direkt nebeneinander | Die Elemente liegen verstreut und sind über Zeiger verbunden |
| Lesen des i-ten Elements | O(1): Die Adresse ist Startadresse + i × Elementgröße | O(n): vom Anfang aus i-mal den Zeigern folgen |
| Suche nach einem Wert | O(n) mit linearer Suche, wenn unsortiert; O(log n) mit binärer Suche, wenn sortiert | O(n) auch bei Sortierung; binäre Suche ist nicht möglich, da man nicht direkt in die Mitte springen kann |
| Einfügen oder Löschen in der Mitte | O(n): Die dahinterliegenden Elemente werden einzeln verschoben | O(1), wenn die Position (das vorhergehende Element) bekannt ist; nur Zeiger ändern sich |
| Anhängen am Ende | O(1), wenn Platz frei ist; ein dynamisches Array, das seine Kapazität jeweils verdoppelt, kopiert gelegentlich alles, ist im Mittel aber O(1) (amortisiert) | O(1), wenn ein Zeiger auf das letzte Element gehalten wird |
| Größenänderung | Die Größe eines Arrays fester Länge wird beim Anlegen festgelegt; zum Vergrößern wird ein neuer Block angelegt und kopiert | Speicher wird pro Element belegt, daher wächst sie nur so weit wie nötig |
| Speicherbedarf | Nur die Elemente selbst (ein dynamisches Array hält etwas Reservekapazität) | Zusätzlicher Platz für einen Zeiger pro Element (zwei bei einer doppelt verketteten Liste) |
| Cache-Freundlichkeit | Gut: Die Elemente liegen zusammenhängend, daher nutzen sequenzielle Lesezugriffe Caches und Prefetching gut | Schlecht: Die Elemente liegen oft verstreut, daher kann selbst derselbe O(n)-Durchlauf viel langsamer sein als bei einem Array |
| Typischer Einsatz | Tabellen mit Zugriff per Index, Matrizen und Bilder, Daten zum Sortieren oder für binäre Suche, Implementierung von Stacks und Warteschlangen | Folgen mit häufigem Einfügen und Löschen, Verkettung in Hashtabellen, Verwaltung freien Speichers |
Die Zahlenwerte sind typische Größenordnungen und variieren je nach Prozessgeneration und Produkt.