1016 Stimmen

Verkettung von zwei std::Vektoren

Wie verkette ich zwei std::vector s?

10 Stimmen

Die gegebenen Antworten sind nicht wirklich zusammenhängend. Sie fügen eine Kopie an. Es könnte (aus Gründen der Effizienz) sinnvoll sein, eine std::vector concatenate-Methode zu erstellen, allerdings würde dies eine ausgeklügelte gemeinsame Nutzung der Verwaltung der Knoten erfordern, und das ist wahrscheinlich der Grund, warum dies noch nicht geschehen ist.

16 Stimmen

@FauChristian: Nein, unter Effizienzgesichtspunkten kann es keinen Nutzen geben. Der Vektorspeicher muss kontinuierlich sein, also ist das, was Sie vorschlagen, unmöglich. Wenn Sie "eine ausgeklügelte gemeinsame Nutzung der Verwaltung der Knoten" wollten und die Vektorklasse auf diese Weise ändern würden, würden Sie bei einer Deque landen. Selbst dann ist es sehr schwierig, den Speicher in der vorgeschlagenen Weise wiederzuverwenden, auch wenn es allmählich ein wenig praktikabler wäre. Ich glaube nicht, dass es derzeit implementiert ist. Die Hauptsache ist, dass in einem solchen Sharing von Management-Knoten (eine deque) der Endknoten teilweise leer sein könnte.

18 Stimmen

Bin ich der Einzige, der sich fragt, warum dies nicht als a + b o a.concat(b) in der Standardbibliothek? Vielleicht wäre die Standardimplementierung suboptimal, aber nicht jede Array-Verkettung muss mikro-optimiert sein

1053voto

Robert Gamble Punkte 101657
vector1.insert( vector1.end(), vector2.begin(), vector2.end() );

63 Stimmen

Ich würde nur Code hinzufügen, um zunächst die Anzahl der Elemente zu ermitteln, die jeder Vektor enthält, und Vektor1 so einstellen, dass er die meisten Elemente enthält. Sollten Sie sonst tun Sie tun eine Menge unnötige Kopieren.

45 Stimmen

Ich habe eine Frage. Funktioniert das auch, wenn vector1 und vector2 die gleichen Vektoren sind?

9 Stimmen

Wenn Sie mehrere Vektoren zu einem einzigen zusammenfügen, ist es hilfreich, die reserve zuerst auf den Zielvektor?

310voto

Alex Punkte 2873

Wenn Sie C++11 verwenden und die Elemente verschieben möchten, anstatt sie nur zu kopieren, können Sie std::move_iterator zusammen mit der Beilage (oder Kopie):

#include <vector>
#include <iostream>
#include <iterator>

int main(int argc, char** argv) {
  std::vector<int> dest{1,2,3,4,5};
  std::vector<int> src{6,7,8,9,10};

  // Move elements from src to dest.
  // src is left in undefined but safe-to-destruct state.
  dest.insert(
      dest.end(),
      std::make_move_iterator(src.begin()),
      std::make_move_iterator(src.end())
    );

  // Print out concatenated vector.
  std::copy(
      dest.begin(),
      dest.end(),
      std::ostream_iterator<int>(std::cout, "\n")
    );

  return 0;
}

Für das Beispiel mit den Ints ist dies nicht effizienter, da das Verschieben von Ints nicht effizienter ist als das Kopieren, aber für eine Datenstruktur mit optimierten Verschiebungen kann es das Kopieren unnötiger Zustände vermeiden:

#include <vector>
#include <iostream>
#include <iterator>

int main(int argc, char** argv) {
  std::vector<std::vector<int>> dest{{1,2,3,4,5}, {3,4}};
  std::vector<std::vector<int>> src{{6,7,8,9,10}};

  // Move elements from src to dest.
  // src is left in undefined but safe-to-destruct state.
  dest.insert(
      dest.end(),
      std::make_move_iterator(src.begin()),
      std::make_move_iterator(src.end())
    );

  return 0;
}

Nach dem Verschieben bleibt das Element von src in einem undefinierten, aber zerstörungssicheren Zustand, und seine früheren Elemente wurden am Ende direkt in das neue Element von dest übertragen.

14 Stimmen

Die Methode std::make_move_iterator() hat mir geholfen, als ich versucht habe, std::Vektoren von std::unique_ptr zu verketten.

4 Stimmen

Was ist der Unterschied zwischen diesem und std::move(src.begin(), src.end(), back_inserter(dest)) ?

4 Stimmen

@kshenoy, insert könnte die erforderliche Menge an Speicher in einem Zug zuweisen. Wenn back_inserter könnte zu mehreren Umschichtungen führen

191voto

Tom Ritter Punkte 97450

Ich würde die Einfügefunktion so etwas wie:

vector<int> a, b;
//fill with data
b.insert(b.end(), a.begin(), a.end());

94voto

Roger Lipscombe Punkte 84868

Oder Sie könnten es verwenden:

std::copy(source.begin(), source.end(), std::back_inserter(destination));

Dieses Muster ist nützlich, wenn die beiden Vektoren nicht genau die gleiche Art von Dingen enthalten, weil man etwas anstelle von std::back_inserter um von einem Typ in den anderen umzuwandeln.

16 Stimmen

Die Kopiermethode ist nicht so gut. Sie ruft push_back mehrfach auf, was bedeutet, dass, wenn viele Elemente eingefügt werden müssen, dies mehrere Neuzuweisungen bedeuten könnte. Es ist besser, insert zu verwenden, da die Vektorimplementierung einige Optimierungen vornehmen könnte, um Neuzuweisungen zu vermeiden. sie könnte Speicher reservieren, bevor sie mit dem Kopieren beginnt

11 Stimmen

@Yogesh: Zugegeben, aber es hindert Sie niemand daran, anzurufen. reserve erstens. Der Grund std::copy ist manchmal nützlich, wenn Sie etwas anderes verwenden wollen als back_inserter .

0 Stimmen

Wenn Sie von "Mehrfachzuweisungen" sprechen, ist das richtig - aber die Anzahl der Zuweisungen ist schlimmstenfalls log(Anzahl der hinzugefügten Einträge) - was bedeutet, dass die Kosten für das Hinzufügen eines Eintrags konstant mit der Anzahl der hinzugefügten Einträge sind. (Machen Sie sich im Grunde keine Gedanken darüber, es sei denn, die Profilerstellung zeigt, dass Sie eine Reserve benötigen).

86voto

Deqing Punkte 12880

Mit C++11 würde ich folgendes vorziehen, um den Vektor b an a anzuhängen:

std::move(b.begin(), b.end(), std::back_inserter(a));

wenn a y b sich nicht überschneiden, und b wird nicht mehr verwendet.


Dies ist std::move de <algorithm> , nicht die üblich std::move de <utility> .

19 Stimmen

Undefiniertes Verhalten, wenn a tatsächlich b ist (was OK ist, wenn Sie wissen, dass das nie passieren kann - aber es lohnt sich, in allgemeinem Code darauf zu achten).

1 Stimmen

@MartinBonner Danke für diesen Hinweis. Wahrscheinlich sollte ich mich wieder dem alten insert die sicherer ist.

0 Stimmen

Fügen Sie einfach folgende Kopfzeile am Anfang ein: #include <iterator>

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X