Ich habe in meinem Buch über C ++ über STL-Container gelesen, insbesondere über den Abschnitt über die STL und ihre Container. Jetzt verstehe ich, dass jeder von ihnen seine eigenen spezifischen Eigenschaften hat, und ich bin kurz davor, sie alle auswendig zu lernen ... Aber was ich noch nicht verstehe, ist, in welchem Szenario jeder von ihnen verwendet wird.
Was ist die Erklärung? Beispielcode wird sehr bevorzugt.
c++
stl
container-data-type
Daniel Sloof
quelle
quelle
Antworten:
Dieser Spickzettel bietet eine ziemlich gute Zusammenfassung der verschiedenen Container.
Im Flussdiagramm unten finden Sie eine Anleitung zur Verwendung in verschiedenen Verwendungsszenarien:
Erstellt von David Moore und lizenziert CC BY-SA 3.0
quelle
vector
eher leer als leer sein. stackoverflow.com/questions/10699265/…unordered_map
undunordered_set
(und ihre Multi-Varianten), die nicht im Flussdiagramm enthalten sind, aber gute Tipps sind, wenn Sie sich nicht um die Reihenfolge kümmern, sondern Elemente nach Schlüssel suchen müssen. Ihre Suche ist normalerweise O (1) anstelle von O (log n).Hier ist ein Flussdiagramm, das von der von mir erstellten Version von David Moore (siehe oben) inspiriert ist und (meistens) mit dem neuen Standard (C ++ 11) auf dem neuesten Stand ist. Dies ist nur meine persönliche Einstellung, es ist nicht unbestreitbar, aber ich dachte, es könnte für diese Diskussion wertvoll sein:
quelle
vector (sorted)
ist ein bisschen unvereinbar mit dem Rest. Es ist kein anderer Containertyp, nur derselbe,std::vector
aber sortiert. Noch wichtiger ist, ich verstehe nicht, warum man einestd::set
für geordnete Iteration nicht verwenden kann , wenn dies das Standardverhalten der Iteration durch eine Menge ist. Sicher, wenn es in der Antwort um den ordnungsgemäßen Zugriff auf die Werte des Containertrogs geht[]
, können Sie dies nur mit einem Soted tunstd::vector
. Aber in jedem Fall sollte die Entscheidung unmittelbar nach der Frage "Bestellung ist erforderlich" getroffen werdenEinfache Antwort: Verwenden Sie
std::vector
für alles, es sei denn, Sie haben einen wirklichen Grund, etwas anderes zu tun.Wenn Sie einen Fall finden, in dem Sie denken: "Gee,
std::vector
funktioniert hier wegen X nicht gut", gehen Sie auf der Grundlage von X.quelle
std::remove_if
ist dem Ansatz "Während der Iteration löschen" fast immer überlegen.Schauen Sie sich Effective STL von Scott Meyers an. Es ist gut zu erklären, wie man die STL benutzt.
Wenn Sie eine bestimmte / unbestimmte Anzahl von Objekten speichern möchten und niemals Objekte löschen möchten, ist ein Vektor genau das, was Sie möchten. Es ist der Standardersatz für ein C-Array und funktioniert wie eines, läuft aber nicht über. Sie können die Größe auch vorher mit Reserve () einstellen.
Wenn Sie eine unbestimmte Anzahl von Objekten speichern möchten, diese aber hinzufügen und löschen möchten, möchten Sie wahrscheinlich eine Liste ... weil Sie ein Element löschen können, ohne die folgenden Elemente zu verschieben - im Gegensatz zu Vektoren. Es benötigt jedoch mehr Speicher als ein Vektor, und Sie können nicht nacheinander auf ein Element zugreifen.
Wenn Sie eine Reihe von Elementen nehmen und nur die eindeutigen Werte dieser Elemente finden möchten, reicht es aus, sie alle in eine Menge einzulesen und sie auch für Sie zu sortieren.
Wenn Sie viele Schlüssel-Wert-Paare haben und diese nach Schlüssel sortieren möchten, ist eine Zuordnung nützlich ... aber sie enthält nur einen Wert pro Schlüssel. Wenn Sie mehr als einen Wert pro Schlüssel benötigen, können Sie einen Vektor / eine Liste als Wert in der Karte haben oder eine Multimap verwenden.
Es ist nicht in der STL enthalten, aber es ist im TR1-Update der STL enthalten: Wenn Sie viele Schlüssel-Wert-Paare haben, werden Sie nach Schlüssel suchen, und Sie interessieren sich möglicherweise nicht für deren Reihenfolge möchte einen Hash verwenden - das ist tr1 :: unordered_map. Ich habe es mit Visual C ++ 7.1 verwendet, wo es stdext :: hash_map hieß. Es hat eine Suche von O (1) anstelle einer Suche von O (log n) für die Karte.
quelle
hash_map
keine sehr gute Implementierung ist. Ich hoffe, sie haben es besser gemachtunordered_map
.list
tut. Eher eklatanter Fehler da.Ich habe das Flussdiagramm neu gestaltet, um 3 Eigenschaften zu haben:
Das Flussdiagramm:
Weitere Informationen finden Sie unter diesem Link .
quelle
Ein wichtiger Punkt nur kurz so weit erwähnt, ist , dass , wenn Sie zusammenhängenden Speicher erfordern (wie ein C - Array gibt), dann können Sie nur verwenden
vector
,array
oderstring
.Verwenden Sie
array
diese Option, wenn die Größe zur Kompilierungszeit bekannt ist.Verwenden
string
Sie diese Option, wenn Sie nur mit Zeichentypen arbeiten müssen und eine Zeichenfolge benötigen, nicht nur einen Allzweckcontainer.Verwendung
vector
in allen anderen Fällen (vector
sollte in den meisten Fällen ohnehin die Standardauswahl für Container sein).Mit allen drei können Sie
data()
die Elementfunktion verwenden, um einen Zeiger auf das erste Element des Containers zu erhalten.quelle
Es hängt alles davon ab, was Sie speichern möchten und was Sie mit dem Container tun möchten. Hier sind einige (sehr nicht erschöpfende) Beispiele für die Containerklassen, die ich am häufigsten verwende:
vector
: Kompaktes Layout mit geringem oder keinem Speicheraufwand pro enthaltenem Objekt. Effizient zu iterieren. Das Anhängen, Einfügen und Löschen kann insbesondere bei komplexen Objekten teuer sein. Günstig, um ein enthaltenes Objekt anhand des Index zu finden, z. B. myVector [10]. Verwenden Sie, wo Sie ein Array in C verwendet hätten. Gut, wo Sie viele einfache Objekte haben (z. B. int). Vergessen Sie nicht, es zu verwenden,reserve()
bevor Sie dem Container viele Objekte hinzufügen.list
: Kleiner Speicheraufwand pro enthaltenem Objekt. Effizient zu iterieren. Anhängen, Einfügen und Löschen sind billig. Verwenden Sie, wo Sie eine verknüpfte Liste in C verwendet hätten.set
(undmultiset
): Signifikanter Speicheraufwand pro enthaltenem Objekt. Verwenden Sie diese Option, um schnell herauszufinden, ob dieser Container ein bestimmtes Objekt enthält, oder um Container effizient zusammenzuführen.map
(undmultimap
): Signifikanter Speicheraufwand pro enthaltenem Objekt. Verwenden Sie diese Option, um Schlüssel-Wert-Paare zu speichern und Werte nach Schlüssel schnell nachzuschlagen.Das von zdan vorgeschlagene Flussdiagramm auf dem Spickzettel bietet eine ausführlichere Anleitung.
quelle
Eine Lektion, die ich gelernt habe, ist: Versuchen Sie, sie in eine Klasse einzupacken, da das Ändern des Containertyps an einem schönen Tag große Überraschungen bringen kann.
Es kostet im Voraus nicht viel und spart Zeit beim Debuggen, wenn Sie eine Unterbrechung durchführen möchten, wenn jemand die Operation x für diese Struktur ausführt.
Zur Auswahl der perfekten Datenstruktur für einen Job:
Jede Datenstruktur bietet einige Operationen, die zeitlich unterschiedlich sein können:
O (1), O (lg N), O (N) usw.
Sie müssen im Wesentlichen eine Vermutung anstellen, welche Operationen am häufigsten ausgeführt werden, und eine Datenstruktur verwenden, die diese Operation als O (1) hat.
Einfach, nicht wahr (-:
quelle
auto myIterator = whateverCollection.begin(); // <-- immune to changes of container type
typedef Collection<Foo*> CollectionOfFoo;
ausreichend?Ich habe das fantastische Flussdiagramm von Mikael Persson erweitert . Ich habe einige Containerkategorien, den Array-Container und einige Notizen hinzugefügt. Wenn Sie eine eigene Kopie wünschen, finden Sie hier die Google-Zeichnung. Danke, Mikael, dass du die Grundlagen geschaffen hast! C ++ Container Picker
quelle
Ich habe dies in einer anderen Frage beantwortet, die als Dup dieser Frage markiert ist. Ich finde es jedoch schön, einige gute Artikel über die Entscheidung für einen Standardbehälter zu lesen.
Wie @David Thornley antwortete, ist std :: vector der richtige Weg, wenn es keine anderen speziellen Anforderungen gibt. Dies ist der Rat des Entwicklers von C ++, Bjarne Stroustrup, in einem Blog von 2014.
Hier ist der Link zum Artikel https://isocpp.org/blog/2014/06/stroustrup-lists
und zitiere aus diesem,
In den Kommentaren bietet Benutzer @NathanOliver auch einen weiteren guten Blog an, der konkretere Messungen enthält. https://baptiste-wicht.com/posts/2012/12/cpp-benchmark-vector-list-deque.html .
quelle