Wann ist es besser, eine Liste gegen eine LinkedList zu verwenden ?
c#
.net
vb.net
data-structures
linked-list
Jonathan Allen
quelle
quelle
Antworten:
Bearbeiten
Ursprüngliche Antwort ...
Ich habe interessante Ergebnisse gefunden:
Verknüpfte Liste (3,9 Sekunden)
Liste (2,4 Sekunden)
Selbst wenn Sie nur auf Daten zugreifen, ist dies wesentlich langsamer !! Ich sage, benutze niemals eine linkedList.
Hier ist ein weiterer Vergleich, bei dem viele Einfügungen durchgeführt werden (wir planen, ein Element in die Mitte der Liste einzufügen).
Verknüpfte Liste (51 Sekunden)
Liste (7,26 Sekunden)
Verknüpfte Liste mit Verweis auf den Ort, an dem eingefügt werden soll (0,04 Sekunden)
Also nur , wenn Sie auf das Einfügen mehrerer Elemente planen und Sie auch irgendwo die Referenz von dem Sie das Element dann eine verkettete Liste verwenden , um einzufügen. Nur weil Sie viele Elemente einfügen müssen, wird dies nicht schneller, da die Suche nach dem Ort, an dem Sie sie einfügen möchten, einige Zeit in Anspruch nimmt.
quelle
list.AddLast(a);
in den letzten beiden LinkedList-Beispielen? Ich mache es einmal vor der Schleife, wielist.AddLast(new Temp(1,1,1,1));
in der vorletzten LinkedList, aber es sieht (für mich) so aus, als würden Sie doppelt so viele Temp-Objekte in die Schleifen selbst einfügen. (Und wenn ich mich mit einer Test-App noch einmal überprüfe , sicher doppelt so viele in der LinkedList.)I say never use a linkedList.
ist fehlerhaft, wie Ihr späterer Beitrag zeigt. Vielleicht möchten Sie es bearbeiten. 2) Was ist dein Timing? Instanziierung, Addition und Aufzählung in einem Schritt? Instanziierung und Aufzählung sind meistens nicht das, worüber sich die Leute Sorgen machen, das sind einmalige Schritte. Insbesondere das Timing der Einfügungen und Ergänzungen würde eine bessere Idee ergeben. 3) Am wichtigsten ist, dass Sie einer verknüpften Liste mehr als erforderlich hinzufügen. Dies ist ein falscher Vergleich. Verbreitet falsche Vorstellungen über Linkedlist.In den meisten Fällen
List<T>
ist dies nützlicher.LinkedList<T>
Das Hinzufügen / Entfernen von Elementen in der Mitte der ListeList<T>
ist kostengünstiger , während das Hinzufügen / Entfernen von Elementen am Ende der Liste nur kostengünstig möglich ist .LinkedList<T>
ist nur dann am effizientesten, wenn Sie auf sequentielle Daten zugreifen (entweder vorwärts oder rückwärts) - der Direktzugriff ist relativ teuer, da er jedes Mal die Kette durchlaufen muss (daher gibt es keinen Indexer). Da aList<T>
jedoch im Wesentlichen nur ein Array (mit einem Wrapper) ist, ist der Direktzugriff in Ordnung.List<T>
bietet auch eine Menge Unterstützung Methoden -Find
,ToArray
usw; Diese sind jedoch auch fürLinkedList<T>
.NET 3.5 / C # 3.0 über Erweiterungsmethoden verfügbar - das ist also weniger ein Faktor.quelle
List<T>
undT[]
wird scheitern, weil es zu klobig ist (alle eine Platte),LinkedList<T>
wird klagen, weil es zu körnig ist (Platte pro Element).Eine verknüpfte Liste als Liste zu betrachten, kann etwas irreführend sein. Es ist eher wie eine Kette. Tatsächlich wird in .NET
LinkedList<T>
nicht einmal implementiertIList<T>
. Es gibt kein wirkliches Konzept des Index in einer verknüpften Liste, auch wenn es so scheint. Sicherlich akzeptiert keine der in der Klasse bereitgestellten Methoden Indizes.Verknüpfte Listen können einfach oder doppelt verknüpft sein. Dies bezieht sich darauf, ob jedes Element in der Kette nur eine Verbindung zum nächsten (einfach verknüpft) oder zu beiden vorherigen / nächsten Elementen (doppelt verknüpft) hat.
LinkedList<T>
ist doppelt verbunden.Intern
List<T>
wird durch ein Array gesichert. Dies bietet eine sehr kompakte Darstellung im Speicher. Umgekehrt wirdLinkedList<T>
zusätzlicher Speicher zum Speichern der bidirektionalen Verknüpfungen zwischen aufeinanderfolgenden Elementen verwendet. Daher ist der Speicherbedarf von aLinkedList<T>
im Allgemeinen größer als fürList<T>
(mit der Einschränkung,List<T>
dass nicht verwendete interne Array-Elemente zur Verbesserung der Leistung während des Anhängens verwendet werden können).Sie haben auch unterschiedliche Leistungsmerkmale:
Anhängen
LinkedList<T>.AddLast(item)
konstante ZeitList<T>.Add(item)
amortisierte konstante Zeit, linearer Worst-CaseVorbereiten
LinkedList<T>.AddFirst(item)
konstante ZeitList<T>.Insert(0, item)
lineare ZeitEinfügen
LinkedList<T>.AddBefore(node, item)
konstante ZeitLinkedList<T>.AddAfter(node, item)
konstante ZeitList<T>.Insert(index, item)
lineare ZeitEntfernung
LinkedList<T>.Remove(item)
lineare ZeitLinkedList<T>.Remove(node)
konstante ZeitList<T>.Remove(item)
lineare ZeitList<T>.RemoveAt(index)
lineare ZeitAnzahl
LinkedList<T>.Count
konstante ZeitList<T>.Count
konstante ZeitEnthält
LinkedList<T>.Contains(item)
lineare ZeitList<T>.Contains(item)
lineare Zeitklar
LinkedList<T>.Clear()
lineare ZeitList<T>.Clear()
lineare ZeitWie Sie sehen können, sind sie meistens gleichwertig. In der Praxis ist die
LinkedList<T>
Verwendung der API von umständlicher, und Details zu den internen Anforderungen werden in Ihren Code übernommen.Wenn Sie jedoch viele Einfügungen / Entfernungen innerhalb einer Liste vornehmen müssen, bietet dies eine konstante Zeit.
List<T>
bietet lineare Zeit, da zusätzliche Elemente in der Liste nach dem Einfügen / Entfernen gemischt werden müssen.quelle
Verknüpfte Listen ermöglichen das sehr schnelle Einfügen oder Löschen eines Listenmitglieds. Jedes Mitglied in einer verknüpften Liste enthält einen Zeiger auf das nächste Mitglied in der Liste, um ein Mitglied an Position i einzufügen:
Der Nachteil einer verknüpften Liste besteht darin, dass kein wahlfreier Zugriff möglich ist. Um auf ein Mitglied zugreifen zu können, muss die Liste durchlaufen werden, bis das gewünschte Mitglied gefunden wurde.
quelle
Meine vorherige Antwort war nicht genau genug. Es war wirklich schrecklich: D Aber jetzt kann ich eine viel nützlichere und korrektere Antwort posten.
Ich habe einige zusätzliche Tests durchgeführt. Sie können die Quelle über den folgenden Link finden und sie in Ihrer Umgebung erneut überprüfen: https://github.com/ukushu/DataStructuresTestsAndOther.git
Kurze Ergebnisse:
Array muss verwenden:
Liste muss verwendet werden:
LinkedList muss Folgendes verwenden:
Mehr Details:
Interessant zu wissen:
LinkedList<T>
intern ist keine Liste in .NET. Es ist sogar nicht implementiertIList<T>
. Und deshalb gibt es keine Indizes und Methoden, die sich auf Indizes beziehen.LinkedList<T>
ist eine auf Knotenzeigern basierende Sammlung. In .NET ist die Implementierung doppelt verknüpft. Dies bedeutet, dass vorherige / nächste Elemente eine Verknüpfung zum aktuellen Element haben. Und Daten sind fragmentiert - verschiedene Listenobjekte können sich an verschiedenen Stellen des RAM befinden. Außerdem wird mehr SpeicherLinkedList<T>
als fürList<T>
oder Array verwendet.List<T>
in .Net ist Javas Alternative zuArrayList<T>
. Dies bedeutet, dass dies ein Array-Wrapper ist. Es wird also im Speicher als ein zusammenhängender Datenblock zugewiesen. Wenn die zugewiesene Datengröße 85000 Byte überschreitet, wird sie in den Heap für große Objekte verschoben. Abhängig von der Größe kann dies zu einer Fragmentierung des Heapspeichers führen (eine leichte Form des Speicherverlusts). Bei einer Größe <85000 Byte bietet dies gleichzeitig eine sehr kompakte und schnell zugängliche Darstellung im Speicher.Ein einzelner zusammenhängender Block wird für die Direktzugriffsleistung und den Speicherverbrauch bevorzugt, aber für Sammlungen, deren Größe regelmäßig geändert werden muss, muss eine Struktur wie ein Array im Allgemeinen an einen neuen Speicherort kopiert werden, während eine verknüpfte Liste nur den Speicher für den neu eingefügten Speicher verwalten muss / gelöschte Knoten.
quelle
Der Unterschied zwischen List und LinkedList liegt in der zugrunde liegenden Implementierung. Liste ist eine Array-basierte Sammlung (ArrayList). LinkedList ist eine auf Knotenzeigern basierende Sammlung (LinkedListNode). Auf API-Ebene sind beide ziemlich gleich, da beide die gleichen Schnittstellen wie ICollection, IEnumerable usw. implementieren.
Der Hauptunterschied kommt, wenn Leistung wichtig ist. Wenn Sie beispielsweise die Liste implementieren, die eine schwere "INSERT" -Operation aufweist, übertrifft LinkedList List. Da LinkedList dies in O (1) -Zeit tun kann, muss List möglicherweise die Größe des zugrunde liegenden Arrays erweitern. Für weitere Informationen / Details möchten Sie möglicherweise den algorithmischen Unterschied zwischen LinkedList- und Array-Datenstrukturen nachlesen. http://en.wikipedia.org/wiki/Linked_list and Array
Ich hoffe das hilft,
quelle
Add
immer am Ende eines vorhandenen Arrays steht.List
ist dabei "gut genug", auch wenn nicht O (1). Das ernsthafte Problem tritt auf, wenn Sie vieleAdd
s benötigen , die nicht am Ende sind. Marc wird darauf hingewiesen , dass die Notwendigkeit zu bewegen vorhandene Daten jedes Mal , wenn Sie ein (nicht nur , wenn Resize benötigt wird) ist eine erhebliche LeistungskostenList
.Der Hauptvorteil von verknüpften Listen gegenüber Arrays besteht darin, dass die Verknüpfungen uns die Möglichkeit bieten, die Elemente effizient neu anzuordnen. Sedgewick, p. 91
quelle
Ein häufiger Umstand bei der Verwendung von LinkedList ist folgender:
Angenommen, Sie möchten viele bestimmte Zeichenfolgen aus einer Liste von Zeichenfolgen mit einer großen Größe entfernen, z. B. 100.000. Die zu entfernenden Zeichenfolgen können in HashSet dic nachgeschlagen werden, und es wird angenommen, dass die Liste der zu entfernenden Zeichenfolgen zwischen 30.000 und 60.000 solcher zu entfernenden Zeichenfolgen enthält.
Was ist dann die beste Art von Liste zum Speichern der 100.000 Zeichenfolgen? Die Antwort lautet LinkedList. Wenn sie in einer ArrayList gespeichert sind, würde das Durchlaufen und Entfernen von übereinstimmenden Strings bis zu Milliarden von Operationen erfordern, während mit einem Iterator und der remove () -Methode nur etwa 100.000 Operationen erforderlich sind.
quelle
RemoveAll
die Elemente einfach aus a entfernen,List
ohne viele Elemente zu verschieben, oderWhere
aus LINQ eine zweite Liste erstellen. Die Verwendung von aLinkedList
verbraucht jedoch dramatisch mehr Speicher als andere Arten von Sammlungen, und der Verlust der Speicherlokalität bedeutet, dass die Iteration merklich langsamer ist, was die Leistung erheblich verschlechtert als die von aList
.RemoveAll
in Java ein Äquivalent gibt .RemoveAll
nicht möglich istList
, können Sie einen "Komprimierungs" -Algorithmus ausführen, der wie Toms Schleife aussieht, jedoch zwei Indizes enthält und Elemente verschieben muss, die einzeln im internen Array der Liste gespeichert werden sollen. Die Effizienz ist O (n), genau wie Toms Algorithmus fürLinkedList
. In beiden Versionen dominiert die Zeit zum Berechnen des HashSet-Schlüssels für die Zeichenfolgen. Dies ist kein gutes Beispiel für die VerwendungLinkedList
.Wenn Sie einen integrierten indizierten Zugriff, eine Sortierung (und nach dieser binären Suche) und die Methode "ToArray ()" benötigen, sollten Sie List verwenden.
quelle
Im Wesentlichen ist ein
List<>
in .NET ein Wrapper über ein Array . ALinkedList<>
ist eine verknüpfte Liste . Es stellt sich also die Frage, was der Unterschied zwischen einem Array und einer verknüpften Liste ist und wann ein Array anstelle einer verknüpften Liste verwendet werden sollte. Wahrscheinlich sind die beiden wichtigsten Faktoren bei Ihrer Entscheidung, welche Sie verwenden möchten, folgende:quelle
Dies ist von Tono Nam angepasst akzeptierter Antwort übernommen, die einige falsche Messungen korrigiert.
Die Prüfung:
Und der Code:
Sie können sehen, dass die Ergebnisse mit der theoretischen Leistung übereinstimmen, die andere hier dokumentiert haben. Ganz klar -
LinkedList<T>
gewinnt bei Einfügungen viel Zeit. Ich habe nicht getestet, ob sie aus der Mitte der Liste entfernt wurden, aber das Ergebnis sollte das gleiche sein. NatürlichList<T>
hat andere Bereiche, in denen es viel besser funktioniert, wie O (1) Direktzugriff.quelle
Verwenden Sie,
LinkedList<>
wennToken Stream
.Für alles andere ist es besser zu verwenden
List<>
.quelle
LinkedListNode<T>
Objekte in Ihrem Code verfolgen . Wenn Sie dies tun können, ist es viel besser als die VerwendungList<T>
, insbesondere für sehr lange Listen, in denen häufig Einfügungen / Entfernungen vorgenommen werden.node.Value
wann immer Sie das ursprüngliche Element möchten). Sie schreiben den Algorithmus also neu, um mit Knoten und nicht mit Rohwerten zu arbeiten.Ich stimme den meisten der oben genannten Punkte zu. Und ich stimme auch zu, dass List in den meisten Fällen eine naheliegendere Wahl ist.
Aber ich möchte nur hinzufügen, dass es viele Fälle gibt, in denen LinkedList für eine bessere Effizienz eine weitaus bessere Wahl ist als List.
Hoffe, jemand würde diese Kommentare nützlich finden.
quelle
So viele durchschnittliche Antworten hier ...
Einige Implementierungen von verknüpften Listen verwenden zugrunde liegende Blöcke von vorab zugewiesenen Knoten. Wenn sie dies nicht tun, ist die konstante Zeit / lineare Zeit weniger relevant, da die Speicherleistung schlecht und die Cache-Leistung noch schlechter ist.
Verwenden Sie verknüpfte Listen, wenn
1) Sie möchten Gewindesicherheit. Sie können bessere thread-sichere Algen erstellen. Sperrkosten dominieren eine Liste gleichzeitiger Stile.
2) Wenn Sie eine große Warteschlange wie Strukturen haben und die ganze Zeit irgendwo anders als am Ende entfernen oder hinzufügen möchten. > 100K-Listen existieren, sind aber nicht so häufig.
quelle
Ich stellte eine ähnliche Frage zur Leistung der LinkedList-Sammlung und stellte fest, dass Steven Clearys C # -Implement von Deque eine Lösung war. Im Gegensatz zur Warteschlangensammlung ermöglicht Deque das Ein- und Ausschalten von Elementen vorne und hinten. Es ähnelt der verknüpften Liste, bietet jedoch eine verbesserte Leistung.
quelle
Deque
die "der verknüpften Liste ähnlich ist, aber eine verbesserte Leistung aufweist" . Bitte qualifizieren diese Aussage:Deque
ist eine bessere Leistung alsLinkedList
, für Ihre spezifischen Code . Wenn Sie Ihrem Link folgen, sehen Sie, dass Sie zwei Tage später von Ivan Stoev erfahren haben, dass dies keine Ineffizienz von LinkedList war, sondern eine Ineffizienz in Ihrem Code. (Und selbst wenn es eine Ineffizienz von LinkedList gewesen wäre, würde dies keine allgemeine Aussage rechtfertigen, dass Deque effizienter ist; nur in bestimmten Fällen.)