Relative Leistung von std::vector vs. std::list vs. std::slist?

Lesezeit: 8 Minuten

Gibt es für eine einfache verkettete Liste, bei der kein wahlfreier Zugriff auf Listenelemente erforderlich ist, wesentliche Vorteile (Leistung oder sonstiges) durch die Verwendung von std::list anstatt std::vector? Wenn ein Rückwärtsdurchlauf erforderlich ist, wäre es effizienter zu verwenden std::slist und reverse() die Liste vor dem Iterieren über ihre Elemente?

  • (Später Kommentar, nur fürs Protokoll): Link zu einem Vortrag von Bjarne Stroustrup: „Why you should Avoid Linked Lists“, wo er behauptet, Vektoren seien immer besser als Listen. Als Grund gibt er an, dass im Durchschnitt die Suche nach dem Einfügepunkt den Aufwand dominiert und das Verschieben von Elementen (in Vektoren) unbedeutend ist im Vergleich. Außerdem: Cache Misses, aber das wird bereits in der Antwort unten erwähnt. Video: youtube.com/watch?v=YQs6IC-vgmo

    – Möre

    16. Januar 14 um 13:04 Uhr


  • Auch wenn list fast immer langsamer ist als vector (außer wenn Sie ein hohes Maß an Splicing durchführen), gibt es einen Punkt, an dem Sie unbedingt eine Liste BENÖTIGEN: stabile Iteratoren. Wenn Sie Kopien von Iteratoren aufbewahren müssen, die immer auf dasselbe Element zeigen (sofern es nicht entfernt wird), kann dies kein Garantievektor bieten (z. B. kann ein Aufruf von push_back alle Iteratoren ungültig machen). Die Verwendung von Speicherpools kann die Geschwindigkeit einer Liste viel näher an die eines Vektors bringen.

    – coderforlife

    1. Juli 14 um 22:00 Uhr

Relative Leistung von stdvector vs stdlist vs stdslist
Motti

Wie üblich besteht die beste Antwort auf Leistungsfragen darin, beide Implementierungen für Ihren Anwendungsfall zu profilieren und zu sehen, welche schneller ist.

Im Allgemeinen, wenn Sie Einfügungen in die Datenstruktur haben (außer am Ende). vector kann langsamer sein, sonst in den meisten Fällen vector wird voraussichtlich besser abschneiden als list wenn auch nur für Probleme mit der Datenlokalitätbedeutet dies, dass, wenn zwei Elemente, die im Datensatz benachbart sind, im Speicher benachbart sind, das nächste Element bereits im Cache des Prozessors ist und den Speicher nicht in den Cache auslagern muss.

Denken Sie auch daran, dass der Platzbedarf für a vector konstant ist (3 Zeiger), während der Raumaufwand für a list für jedes Element bezahlt wird, verringert dies auch die Anzahl vollständiger Elemente (Daten plus Overhead), die sich gleichzeitig im Cache befinden können.

  • Denken Sie auch daran, dass selbst Einfügungen in einem Vektor schneller sind als in einer verknüpften Liste, wenn die Stelle zum Einfügen gesucht werden muss. Wenn Sie beispielsweise eine Reihe zufälliger Ganzzahlen nehmen und sie in sortierter Reihenfolge in einen Vektor oder eine verknüpfte Liste einfügen, ist der Vektor immer schneller, unabhängig von der Anzahl der Elemente insgesamt, aufgrund von Cache-Fehlern bei der Suche nach dem Einfügepunkt die verlinkte Liste.

    – Thalia

    29. September 12 um 22:45 Uhr

  • So ziemlich der einzige Ort, an dem eine verknüpfte Liste schneller ist, ist, wenn Sie viel Spleißen durchführen, da dies nicht mit einer großen Anzahl von Cache-Fehlern verbunden ist und jedes Spleißen eine konstante Zeitoperation ist (die eine große Anzahl von verschieben kann Elemente von einer verknüpften Liste zu einer anderen).

    – Thalia

    29. September 12 um 22:47 Uhr

  • “Denken Sie auch daran, dass der Platzbedarf für einen Vektor konstant ist.” Nur wenn Sie sehr, sehr vorsichtig sind. Für den gelegentlichen Gebrauch hat es linearen Raum oben, genau wie a list. Siehe: Amortisierter linearer Push_back.

    – Muhende Ente

    13. März 17 um 21:46 Uhr

  • @MooingDuck da hast du im schlimmsten Fall Recht vector wird doppelt so viel Speicherplatz zuweisen, wie es benötigt, aber alles andere als ein konstanter Teil dieses Speicherplatzes ist kalt und verursacht keine zusätzlichen Cache-Treffer.

    – Motti

    14. März 17 um 08:22 Uhr

Relative Leistung von stdvector vs stdlist vs stdslist
Sam

Die Standarddatenstruktur, an die man in C++ denken sollte, ist die Vektor.

Beachten Sie die folgenden Punkte …

1]Durchquerung:

Listenknoten sind überall im Speicher verstreut und daher führt die Listendurchquerung dazu Cache-Fehlschläge. Aber das Durchlaufen von Vektoren ist glatt.

2]Einfügen und Löschen:

Durchschnittlich 50 % der Elemente müssen verschoben werden, wenn Sie das zu einem Vektor machen, aber Caches sind sehr gut darin! Aber mit Listen müssen Sie Traverse bis zum Einfügen/Löschen… also nochmal… cache misses! Und überraschenderweise gewinnen Vektoren auch diesen Fall!

3]Lagerung:

Wenn Sie Listen verwenden, gibt es 2 Zeiger pro Element (vorwärts und rückwärts), sodass eine Liste viel größer ist als ein Vektor! Vektoren benötigen nur etwas mehr Speicher als die eigentlichen Elemente benötigen.

Sie sollten einen Grund haben, keinen Vektor zu verwenden.


Bezug:
Ich habe dies in einem Vortrag von The Lord Bjarne Stroustrup gelernt: https://youtu.be/0iWb_qi2-uI?t=2680

  • Ich glaube, Sie meinen Cache-Miss, aber als Indie-Spieleentwickler hatte der Code, den ich schreibe, auch einige Cash-Miss.

    – Sam Washburn

    30. März ’13 um 5:00 Uhr

  • java.dzone.com/articles/c-benchmark-%E2%80%93-stdvector-vs So ähnlich wie Bjarne sagt, aber mit besseren Zahlen und besserem Quellcode für die Tests.

    – Gulgi

    2. Juli 13 um 11:48 Uhr

  • @gulgi, dieser Link verdient eine separate Antwort, nicht nur einen Kommentar. Es wäre schön, die Grafik und kurze Erklärungen hier auf Stackoverflow zu haben.

    – Serge Rogatch

    7. August 17 um 19:14 Uhr

Einfach nein. List hat Vorteile gegenüber Vector, aber sequentieller Zugriff gehört nicht dazu – wenn das alles ist, was Sie tun, dann ist ein Vector besser.

Ein Vektor ist jedoch teurer, um zusätzliche Elemente hinzuzufügen als eine Liste, insbesondere wenn Sie in der Mitte einfügen.

Verstehen Sie, wie diese Sammlungen implementiert werden: Ein Vektor ist ein sequentielles Array von Daten, eine Liste ist ein Element, das die Daten und Zeiger auf die nächsten Elemente enthält. Sobald Sie das verstanden haben, werden Sie verstehen, warum Listen gut für Einfügungen und schlecht für wahlfreien Zugriff sind.

(Die umgekehrte Iteration eines Vektors ist also genau die gleiche wie die Vorwärtsiteration – der Iterator subtrahiert jedes Mal nur die Größe der Datenelemente, die Liste muss immer noch über den Zeiger zum nächsten Element springen.)

  • Dies ist die offensichtliche und in 99% der Fälle richtige Antwort. Wenn Sie eine Rückwärtstraversierung benötigen, führen Sie Ihre for-Schleife rückwärts aus. Arrays/Vektoren bieten wahlfreien Zugriff, sehr schnellen sequentiellen Zugriff und ebenso schnellen sequentiellen Zugriff von jedem zufälligen Startpunkt im Vektor. Liked-Listen haben nur eine Stärke, und das ist das Löschen von Mitgliedern oder das Einfügen von Mitgliedern an irgendeinem Punkt entlang der Liste. Sie saugen ziemlich viel an allem anderen. Langsam, langsam, langsam. Das Erweitern eines Arrays/Vektors ist so einfach wie ein neues malloc() und memmove(). Mit Vprime, Vgrow können Sie sie einfach neu zuweisen und hin und her kopieren.

    Benutzer1899861

    19. August 13 um 6:27 Uhr

1644075669 241 Relative Leistung von stdvector vs stdlist vs stdslist
jam

Wenn Sie eine Rückwärtstraversierung benötigen, ist eine Slist wahrscheinlich nicht die Datenstruktur für Sie.

Eine herkömmliche (doppelt) verknüpfte Liste gibt Ihnen überall in der Liste eine konstante Einfüge- und Löschzeit; Ein Vektor gibt nur amortisiertes Einfügen und Löschen in konstanter Zeit am Ende der Liste. Für einen Vektor ist die Insertions- und Löschzeit irgendwo anders als am Ende linear. Das ist nicht die ganze Geschichte; es gibt auch konstante Faktoren. Ein Vektor ist eine einfachere Datenstruktur, die je nach Kontext Vor- und Nachteile hat.

Der beste Weg, dies zu verstehen, ist zu verstehen, wie sie implementiert werden. Eine verknüpfte Liste hat einen Weiter- und einen Zurück-Zeiger für jedes Element. Ein Vektor hat ein Array von Elementen, die durch einen Index adressiert werden. Daraus können Sie ersehen, dass beide eine effiziente Vorwärts- und Rückwärtstraversierung durchführen können, während nur ein Vektor einen effizienten Direktzugriff bieten kann. Sie können auch sehen, dass der Speicheraufwand einer verknüpften Liste pro Element ist, während er für den Vektor konstant ist. Und Sie können auch sehen, warum die Einfügungszeit zwischen den beiden Strukturen unterschiedlich ist.

1644075670 805 Relative Leistung von stdvector vs stdlist vs stdslist
Metamorphose

Einige strenge Benchmarks zum Thema:
http://baptiste-wicht.com/posts/2012/12/cpp-benchmark-vector-list-deque.html

Wie von anderen angemerkt wurde, bedeutet zusammenhängender Speicher, dass std::vector für die meisten Dinge besser ist. Es gibt praktisch keinen guten Grund, std::list zu verwenden, außer bei kleinen Datenmengen (bei denen alles in den Cache passt) und/oder bei häufigen Löschungen und Wiedereinfügungen. Komplexitätsgarantien beziehen sich nicht auf die reale Leistung aufgrund des Unterschieds zwischen Cache- und Hauptspeichergeschwindigkeiten (200x) und wie sich zusammenhängender Speicherzugriff auf die Cache-Nutzung auswirkt. Sehen Sie, wie Chandler Carruth (google) hier über das Problem spricht:
https://www.youtube.com/watch?v=fHNmRkzxHWs

Und Mike Actons Data Oriented Design Vortrag hier:
https://www.youtube.com/watch?v=rX0ItVEVjHc

1644075670 152 Relative Leistung von stdvector vs stdlist vs stdslist
Gemeinschaft

Siehe diese Frage für Details zu den Kosten:
Was sind die Komplexitätsgarantien der Standardcontainer?

Wenn Sie eine Slist haben und diese nun in umgekehrter Reihenfolge durchlaufen möchten, warum ändern Sie den Typ nicht überall auf list?

1644075670 112 Relative Leistung von stdvector vs stdlist vs stdslist
Benutzer2235747

  • std::vector ist wahnsinnig schneller als std::list, um ein Element zu finden
  • std::vector ist bei sehr kleinen Daten immer schneller als std::list
  • std::vector schiebt Elemente immer schneller nach hinten als std::list
  • std::list kommt sehr gut mit großen Elementen zurecht, insbesondere zum Sortieren oder Einfügen vorne

Notiz: Wenn Sie mehr über Leistung erfahren möchten, würde ich empfehlen, zu sehen Dies

.

784930cookie-checkRelative Leistung von std::vector vs. std::list vs. std::slist?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy