Angenommen, ich habe eine Größe std::vector
(nennen wir es myVec
) N
. Was ist der einfachste Weg, einen neuen Vektor zu konstruieren, der aus einer Kopie der Elemente X bis Y besteht, wobei 0 <= X <= Y <= N-1? Zum Beispiel myVec [100000]
durch myVec [100999]
in einem Vektor der Größe 150000
.
Wenn dies mit einem Vektor nicht effizient durchgeführt werden kann, gibt es einen anderen STL-Datentyp, den ich stattdessen verwenden sollte?
Antworten:
Es ist eine O (N) -Operation, um den neuen Vektor zu konstruieren, aber es gibt keinen besseren Weg.
quelle
O(Y-X)
oder wir würden sagenO(Z) where Z=Y-X
.vector<T> newVec(myVec.begin() + 100000, myVec.begin() + 101000);
?Verwenden Sie einfach den Vektorkonstruktor.
quelle
operator[]
eine Referenz zurückgegeben wird. Nur an dem Punkt, an dem Sie die Referenz lesen oder schreiben, wird dies zu einer Zugriffsverletzung. Da wir beides nicht tun, sondern stattdessen die Adresse erhalten, haben wir UB nicht aufgerufen.std::vector<T>(input_iterator, input_iterator)
, in Ihrem Fallfoo = std::vector<T>(myVec.begin () + 100000, myVec.begin () + 150000);
, sehen Sie zum Beispiel hierquelle
In diesen Tagen verwenden wir
span
s! Sie würden also schreiben:um eine Spanne von 1000 Elementen des gleichen Typs wie
myvec
's zu erhalten. Oder eine knappere Form:(aber ich mag das nicht so sehr, da die Bedeutung jedes numerischen Arguments nicht ganz klar ist; und es wird schlimmer, wenn die Länge und start_pos in der gleichen Größenordnung liegen.)
Denken Sie jedoch daran, dass dies keine Kopie ist, sondern nur eine Ansicht der Daten im Vektor. Seien Sie also vorsichtig. Wenn Sie eine tatsächliche Kopie wünschen, können Sie Folgendes tun:
Anmerkungen:
gsl
steht für Guidelines Support Library. Weitere Informationengsl
finden Sie unter: http://www.modernescpp.com/index.php/c-core-guideline-the-guidelines-support-library .gsl
finden Sie unter: https://github.com/Microsoft/GSLspan
. Sie würdenstd::span
und#include <span>
eher als#include <gsl/span>
.std::vector
hat eine Unmenge von Konstruktoren, es ist super einfach, in einen zu fallen, den Sie nicht verwenden wollten, seien Sie also vorsichtig.quelle
cbegin
undcend
nur für das Prinzip;)std::cbegin
etc sogar.Wenn beide nicht geändert werden sollen (kein Hinzufügen / Löschen von Elementen - das Ändern vorhandener Elemente ist in Ordnung, solange Sie auf Threading-Probleme achten), können Sie einfach
data.begin() + 100000
und weitergebendata.begin() + 101000
und so tun, als wären sie dasbegin()
undend()
eines kleineren Vektors.Da die Vektorspeicherung garantiert zusammenhängend ist, können Sie einfach ein Array mit 1000 Elementen übergeben:
Beide Techniken benötigen eine konstante Zeit, erfordern jedoch, dass die Datenlänge nicht zunimmt, was eine Neuzuweisung auslöst.
quelle
Diese Diskussion ist ziemlich alt, aber die einfachste erwähnte noch nicht, mit list-Initialisierung :
Es erfordert c ++ 11 oder höher.
Anwendungsbeispiel:
Ergebnis:
quelle
Sie haben nicht erwähnt, um welchen Typ es sich
std::vector<...> myVec
handelt, aber wenn es sich um einen einfachen Typ oder eine Struktur / Klasse handelt, die keine Zeiger enthält, und Sie die beste Effizienz erzielen möchten, können Sie eine direkte Speicherkopie erstellen (die meiner Meinung nach schneller ist als die andere Antworten). Hier ist ein allgemeines Beispiel dafür,std::vector<type> myVec
wotype
in diesem Fall istint
:quelle
std::vector(myVec.begin () + 100000, myVec.begin () + 150000);
, die längere Version dieses Modells nicht genau dieselbe Assembly ergeben würde.std::vector<>(iter, iter)
zumemmove()
gegebenenfalls (wenn Konstruktor ist trivial, für eine geeignete Definition trivial).memcpy
.std::copy
Wenn Sie einen oder einen Konstruktor ausführen, der einen Bereich akzeptiert (zwei Iteratoren), verschwören sich der Compiler und die std.library, ummemcpy
gegebenenfalls aufzurufen .Sie könnten einfach verwenden
insert
quelle
Sie können die STL-Kopie mit O (M) -Leistung verwenden, wenn M die Größe des Subvektors ist.
quelle
newvec.reserve(10100 - 10000);
. Es ist definitiv eine Option und technisch wird es funktionieren. Aber welche der beiden empfehlen Sie?Die einzige Möglichkeit, eine Sammlung zu projizieren, die keine lineare Zeit ist, besteht darin, dies träge zu tun, wobei der resultierende "Vektor" tatsächlich ein Subtyp ist, der an die ursprüngliche Sammlung delegiert. Zum Beispiel erstellt die
List#subseq
Methode von Scala eine Teilsequenz in konstanter Zeit. Dies funktioniert jedoch nur, wenn die Sammlung unveränderlich ist und wenn die zugrunde liegende Sprache eine Speicherbereinigung enthält.quelle
Ich wette, der erste Codierer ist jetzt fertig. Für einfache Datentypen ist keine Kopie erforderlich. Setzen Sie einfach auf gute alte C-Code-Methoden zurück.
Übergeben Sie dann den Zeiger p und a len an alles, was einen Subvektor benötigt.
notelen muss sein !!
len < myVec.size()-start
quelle
Vielleicht ist array_view / span in der GSL-Bibliothek eine gute Option.
Hier ist auch eine einzelne Dateiimplementierung : array_view .
quelle
Kopieren Sie Elemente von einem Vektor zu einem anderen leicht
In diesem Beispiel verwende ich einen Vektor von Paaren zu machen , leicht zu verstehen ,
`
„
Wie Sie sehen, können Sie Elemente problemlos von einem Vektor in einen anderen kopieren. Wenn Sie beispielsweise Elemente aus Index 10 bis 16 kopieren möchten, verwenden wir diese
und wenn Sie Elemente von Index 10 bis zu einem Index von Ende möchten, dann in diesem Fall
Ich hoffe, das hilft. Denken Sie nur an den letzten Fall
v.end()-5 > v.begin()+10
quelle
Noch eine Option: Nützlich zum Beispiel beim Wechseln zwischen a
thrust::device_vector
und athrust::host_vector
, wo Sie den Konstruktor nicht verwenden können.Sollte auch Komplexität O (N) sein
Sie können dies mit dem oberen Antwortcode kombinieren
quelle