Załóżmy, że mam std::vector
(nazwijmy to myVec
) rozmiar N
. Jaki jest najprostszy sposób na zbudowanie nowego wektora składającego się z kopii elementów od X do Y, gdzie 0 <= X <= Y <= N-1? Na przykład, myVec [100000]
za pomocą myVec [100999]
w wektorze wielkości 150000
.
Jeśli nie można tego zrobić skutecznie za pomocą wektora, czy istnieje inny typ danych STL, którego powinienem użyć?
Odpowiedzi:
Jest to operacja O (N), aby skonstruować nowy wektor, ale tak naprawdę nie ma lepszego sposobu.
źródło
O(Y-X)
albo powiedzielibyśmyO(Z) where Z=Y-X
.vector<T> newVec(myVec.begin() + 100000, myVec.begin() + 101000);
?Wystarczy użyć konstruktora wektorowego.
źródło
operator[]
zwraca referencję. Tylko w miejscu, w którym czytasz lub piszesz odwołanie, może to stanowić naruszenie zasad dostępu. Ponieważ nie otrzymujemy ani adresu, ale zamiast niego otrzymujemy adres, nie wywołaliśmy UB.std::vector<T>(input_iterator, input_iterator)
, w twoim przypadkufoo = std::vector<T>(myVec.begin () + 100000, myVec.begin () + 150000);
, patrz na przykład tutajźródło
Obecnie używamy
span
s! Więc napisałbyś:aby uzyskać rozpiętość 1000 elementów tego samego typu co
myvec
's. Lub bardziej zwięzła forma:(ale nie podoba mi się to tak bardzo, ponieważ znaczenie każdego argumentu liczbowego nie jest do końca jasne; i gorzej, jeśli długość i początkowe pozycje są tego samego rzędu wielkości).
W każdym razie pamiętaj, że to nie jest kopia, to tylko widok danych w wektorze, więc bądź ostrożny. Jeśli chcesz rzeczywistą kopię, możesz:
Uwagi:
gsl
oznacza bibliotekę obsługi wytycznych. Aby uzyskać więcej informacjigsl
, zobacz: http://www.modernescpp.com/index.php/c-core-guideline-the-guidelines-support-library .gsl
patrz: https://github.com/Microsoft/GSLspan
. Wolałbyś użyćstd::span
i#include <span>
zamiast#include <gsl/span>
.std::vector
ma konstruktorów gazillionowych, bardzo łatwo wpaść w taki, którego nie zamierzałeś używać, więc bądź ostrożny.źródło
cbegin
icend
tylko dla zasady;)std::cbegin
itp. nawet.Jeśli oba nie zostaną zmodyfikowane (bez dodawania / usuwania elementów - modyfikowanie istniejących jest w porządku tak długo, jak zwracać uwagę na kwestie gwintowania), można po prostu przejść wokół
data.begin() + 100000
idata.begin() + 101000
, i udawać, że sąbegin()
iend()
mniejszej wektorze.Lub, ponieważ gwarantuje się, że miejsce na wektor jest ciągłe, możesz po prostu przekazać około 1000 elementów tablicy:
Obie te techniki wymagają stałego czasu, ale wymagają, aby długość danych nie zwiększała się, powodując realokację.
źródło
Ta dyskusja jest dość stara, ale najprostsza nie została jeszcze wspomniana, z inicjalizacją listy :
Wymaga c ++ 11 lub nowszego.
Przykładowe użycie:
Wynik:
źródło
Nie wspomniałeś o tym, jaki
std::vector<...> myVec
jest typ , ale jeśli jest to prosty typ lub struktura / klasa, która nie zawiera wskaźników, i chcesz uzyskać najlepszą wydajność, możesz wykonać bezpośrednią kopię pamięci (co moim zdaniem będzie szybsze niż inne udzielone odpowiedzi). Oto ogólny przykład tego,std::vector<type> myVec
gdzietype
w tym przypadku jestint
:źródło
std::vector(myVec.begin () + 100000, myVec.begin () + 150000);
dłuższa wersja tego produktu nie tworzy dokładnie tego samego zestawu?std::vector<>(iter, iter)
sięmemmove()
w razie potrzeby (jeśli konstruktor jest trywialny, dla odpowiedniej definicji trywialnej).memcpy
. Wykonaj konstruktorstd::copy
lub konstruktor, który akceptuje zakres (dwa iteratory), a kompilator i biblioteka std.li spiskują, aby wywołać,memcpy
gdy jest to właściwe.Możesz po prostu użyć
insert
źródło
Możesz użyć kopiowania STL z wydajnością O (M), gdy M jest rozmiarem subvektora.
źródło
newvec.reserve(10100 - 10000);
. Jest to zdecydowanie opcja i technicznie będzie działać. Ale z dwóch, które zamierzasz polecić?Jedynym sposobem na wyświetlenie kolekcji, która nie jest czasem liniowym, jest zrobienie tego leniwie, gdzie powstały „wektor” jest tak naprawdę podtypem, który przekazuje do oryginalnej kolekcji. Na przykład
List#subseq
metoda Scali tworzy podsekwencję w stałym czasie. Działa to jednak tylko wtedy, gdy kolekcja jest niezmienna i jeśli w podstawowym języku jest używane czyszczenie pamięci.źródło
Publikowanie tego spóźnienia tylko dla innych. Założę się, że pierwszy programista jest już gotowy. W przypadku prostych typów danych nie jest wymagana kopia, wystarczy przywrócić stare dobre metody kodu C.
Następnie przekaż wskaźnik p i soczewkę do czegokolwiek, co wymaga subvektora.
notelen musi być !!
len < myVec.size()-start
źródło
Może dobrym rozwiązaniem jest opcja array_view / span w bibliotece GSL.
Oto także implementacja jednego pliku: array_view .
źródło
Łatwe kopiowanie elementów z jednego wektora na drugi
W tym przykładzie używam wektora par, aby ułatwić zrozumienie
`
„
Jak widać, możesz łatwo kopiować elementy z jednego wektora do drugiego, jeśli na przykład chcesz skopiować elementy z indeksu 10 do 16, wówczas użyjemy
a jeśli chcesz elementy od indeksu 10 do jakiegoś indeksu od końca, to w takim przypadku
mam nadzieję, że to pomoże, pamiętaj tylko w ostatnim przypadku
v.end()-5 > v.begin()+10
źródło
Jeszcze inna opcja: Przydatna na przykład podczas przechodzenia między
thrust::device_vector
a athrust::host_vector
, gdzie nie można użyć konstruktora.Powinny również być złożoności O (N)
Możesz to połączyć z górnym kodem odpowiedzi
źródło