TL;DR aufgrund der modernen Computerarchitektur, ArrayList
für nahezu jeden möglichen Anwendungsfall deutlich effizienter sein - und daher LinkedList
sollte außer in einigen sehr speziellen und extremen Fällen vermieden werden.
Theoretisch hat LinkedList eine O(1) für die add(E element)
Auch das Hinzufügen eines Elements in der Mitte einer Liste sollte sehr effizient sein.
Die Praxis ist ganz anders, denn LinkedList ist eine Cache Feind Datenstruktur. Aus Sicht der Leistung gibt es nur sehr wenige Fälle, in denen LinkedList
könnte leistungsfähiger sein als die Cache-freundlich ArrayList
.
Hier sind die Ergebnisse eines Benchmark-Tests zum Einfügen von Elementen an zufälligen Stellen. Wie Sie sehen können, ist die Array-Liste viel effizienter, obwohl theoretisch jedes Einfügen in der Mitte der Liste ein "Verschieben" der n spätere Elemente des Arrays (kleinere Werte sind besser):
Bei der Arbeit mit einer neueren Hardware-Generation (größere, effizientere Caches) sind die Ergebnisse noch aussagekräftiger:
LinkedList braucht viel mehr Zeit, um die gleiche Aufgabe zu erfüllen. Quelle Quellcode
Hierfür gibt es zwei Hauptgründe:
-
Hauptsächlich - dass die Knotenpunkte des LinkedList
nach dem Zufallsprinzip über den Speicher verstreut sind. RAM ("Random Access Memory") ist nicht wirklich zufällig und Speicherblöcke müssen in den Zwischenspeicher geholt werden. Dieser Vorgang nimmt Zeit in Anspruch, und wenn solche Abrufe häufig erfolgen, müssen die Speicherseiten im Cache ständig ersetzt werden -> Cache-Misses -> Cache ist nicht effizient. ArrayList
Elemente werden in einem kontinuierlichen Speicher gespeichert - und das ist genau das, wofür die moderne CPU-Architektur optimiert ist.
-
Sekundäres LinkedList
erforderlich, um Rückwärts-/Vorwärtszeiger zu halten, was den dreifachen Speicherverbrauch pro gespeichertem Wert bedeutet im Vergleich zu ArrayList
.
DynamicIntArray ist übrigens eine eigene ArrayList-Implementierung, die Int
(primitiver Typ) und nicht Objekte - daher werden alle Daten wirklich nebeneinander gespeichert, was noch effizienter ist.
Ein Schlüsselelement, das man sich merken sollte, ist, dass die Kosten für das Abrufen eines Speicherblocks bedeutender sind als die Kosten für den Zugriff auf eine einzelne Speicherzelle. Aus diesem Grund ist das Lesen von 1 MB sequentiellem Speicher bis zu 400 Mal schneller als das Lesen dieser Datenmenge aus verschiedenen Speicherblöcken:
Latency Comparison Numbers (~2012)
----------------------------------
L1 cache reference 0.5 ns
Branch mispredict 5 ns
L2 cache reference 7 ns 14x L1 cache
Mutex lock/unlock 25 ns
Main memory reference 100 ns 20x L2 cache, 200x L1 cache
Compress 1K bytes with Zippy 3,000 ns 3 us
Send 1K bytes over 1 Gbps network 10,000 ns 10 us
Read 4K randomly from SSD* 150,000 ns 150 us ~1GB/sec SSD
Read 1 MB sequentially from memory 250,000 ns 250 us
Round trip within same datacenter 500,000 ns 500 us
Read 1 MB sequentially from SSD* 1,000,000 ns 1,000 us 1 ms ~1GB/sec SSD, 4X memory
Disk seek 10,000,000 ns 10,000 us 10 ms 20x datacenter roundtrip
Read 1 MB sequentially from disk 20,000,000 ns 20,000 us 20 ms 80x memory, 20X SSD
Send packet CA->Netherlands->CA 150,000,000 ns 150,000 us 150 ms
Quelle: Latenzzahlen, die jeder Programmierer kennen sollte
Um die Sache noch deutlicher zu machen, prüfen Sie bitte den Benchmark für das Hinzufügen von Elementen am Anfang der Liste. Dies ist ein Anwendungsfall, bei dem theoretisch die LinkedList
sollte wirklich glänzen, und ArrayList
sollten schlechte oder sogar schlechtere Ergebnisse aufweisen:
Hinweis: Dies ist ein Benchmark der C++ Std lib, aber meine bisherigen Erfahrungen zeigen, dass die Ergebnisse in C++ und Java sehr ähnlich sind. Quellcode
Das Kopieren einer sequentiellen Speichermenge ist ein Vorgang, der von den modernen CPUs optimiert wurde - was wiederum die Theorie und die Praxis verändert, ArrayList
/ Vector
wesentlich effizienter
Credits: Alle hier veröffentlichten Benchmarks wurden erstellt von Kjell Hedström . Noch mehr Daten finden Sie auf sein Blog
10 Stimmen
Siehe auch: Array versus verknüpfte Liste
12 Stimmen
Siehe dazu das Zitat des Autors von LinkedList stackoverflow.com/a/42529652/2032701 und Sie bekommen ein praktisches Gefühl für das Thema.
2 Stimmen
Niemals. Ich habe es einmal in meinen 25 Jahren Java-Programmierung getan und es im Nachhinein bereut.
0 Stimmen
Bjarne Stroustrup hat dies auch ausgiebig für C++ diskutiert
std::vector
(wie JavaArrayList
) undstd::list
(wie JavaLinkedList
).