Rozważ użycie std :: deque, które zapewnia wstawianie i usuwanie na obu końcach.
Dario
40
Nie, nie rozważaj używania deque tylko dlatego, że możesz chcieć usunąć element, to naprawdę kiepska rada. Istnieje wiele powodów, dla których warto użyć deque lub vector. Prawdą jest, że usunięcie elementu z wektora może być kosztowne - szczególnie jeśli wektor jest duży, ale nie ma powodu, aby sądzić, że deque byłby lepszy niż wektor z przykładu kodu, który właśnie opublikowałeś.
Sowa
6
Na przykład, jeśli masz aplikację graficzną, w której wyświetlasz „listę” rzeczy, w których wstawiasz / usuwasz rzeczy interaktywnie, rozważ przeglądanie listy 50–100 razy na sekundę, aby je wyświetlić, i dodajesz / usuwasz kilka rzeczy razy co minutę. Zatem wdrożenie „listy” jako wektora jest prawdopodobnie lepszym rozwiązaniem pod względem całkowitej wydajności.
Michel Billaud
Odpowiedzi:
705
Aby usunąć pojedynczy element, możesz:
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);// Deletes the second element (vec[1])
vec.erase(vec.begin()+1);
Lub, aby usunąć więcej niż jeden element na raz:
// Deletes the second through third elements (vec[1], vec[2])
vec.erase(vec.begin()+1, vec.begin()+3);
Zauważ też, że binarne nieoperator+ jest koniecznie zdefiniowane dla iteratorów na innych typach kontenerów, takich jak (nie możesz tego zrobić na , musisz do tego użyć )list<T>::iteratorlist.begin() + 2std::liststd::advance
bobobobo
czy twierdzisz, że „+1” jest pierwszym elementem myVector [0] lub faktyczną pozycją myVector [1]
Karl Morrison
2
Z góry musisz zapisać iterator w zmiennej. Jeśli używasz std :: next, możesz to zrobić w jednym wierszu: vec.erase (next (begin (vec), 123));
dani
8
Dziękuję wszystkim, którzy odpowiedzieli. Co mamy myśleć o projekcie klasy, gdy tak prosta operacja, jak usunięcie elementu, wymaga przejścia do StackOverflow?
Pierre
5
@Pierre, ponieważ indeks liczbowy określonego elementu nie jest podstawowym modelem dostępu, iteratorem jest. Wszystkie funkcje, które patrzą na elementy kontenera, wykorzystują iteratory tego kontenera. Np.std::find_if
Caleth
212
Metoda kasowania na std :: vector jest przeciążona, więc prawdopodobnie łatwiej jest ją wywołać
Ale ten problem pojawia się bez względu na liczbę elementów.
Zyx 2000
15
jeśli jest tylko jeden element, indeks wynosi 0, więc dostajesz, vec.begin()który jest poprawny.
Anne Quinn
28
Chciałbym, żeby ktoś wspomniał, że vec.erase(0)to nie działa, ale vec.erase(vec.begin()+0)(lub bez +0) działa. W przeciwnym razie nie otrzymam pasującego wywołania funkcji, dlatego tu przyszedłem
qrtLs
@qrtLs vec.erase(0)może się właściwie skompilować, jeśli 0zostanie zinterpretowane jako stała zerowego wskaźnika ...
Max, co sprawia, że ta funkcja jest lepsza niż: template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }Nie twierdzę, że albo jest lepsza, po prostu pytam z osobistego zainteresowania i zwracam najlepszy wynik, jaki może uzyskać to pytanie.
13
@JoeyvG: Ponieważ a vector<T>::iteratorto iterator o dostępie swobodnym, twoja wersja jest w porządku i może nieco jaśniejsza. Ale wersja, którą opublikował Max, powinna działać dobrze, jeśli zmienisz kontener na inny, który nie obsługuje iteratorów o dostępie swobodnym
Lily Ballard,
2
To imo lepsza odpowiedź, ponieważ dotyczy również innych formatów kontenerów. Możesz także użyć std :: next ().
Bim
Znacznie lepsze podejście, ponieważ nie opiera się na elementach wewnętrznych pojemnika.
BartoszKP
std :: zaliczka jest potrzebna tylko, jeśli uważasz, że nie będzie to wektor, tj. lista. Ale jak już to określiłeś, czy operator + nie byłby prostszy? Według tego stackoverflow.com/questions/1668088/ ... możliwe jest zwiększenie wydajności dzięki operatorowi +
Neil McGill
14
eraseSposób zostaną wykorzystane na dwa sposoby:
Kasowanie pojedynczego elementu:
vector.erase( vector.begin()+3);// Deleting the fourth element
Kasowanie zakresu elementów:
vector.erase( vector.begin()+3, vector.begin()+5);// Deleting from fourth element to sixth element
To jest duplikat odpowiedzi prawie 7 lat po zaakceptowanej odpowiedzi. Proszę nie rób tego.
AlastairG,
10
W rzeczywistości erasefunkcja działa dla dwóch profili:
Usuwanie pojedynczego elementu
iterator erase (iterator position);
Usuwanie zakresu elementów
iterator erase (iterator first, iterator last);
Ponieważ std :: vec.begin () oznacza początek kontenera i jeśli chcemy usunąć ity element z naszego wektora, możemy użyć:
vec.erase(vec.begin()+ index);
Jeśli przyjrzysz się uważnie, vec.begin () jest tylko wskaźnikiem do pozycji początkowej naszego wektora, a dodanie do niego wartości i zwiększa wskaźnik do pozycji i, więc zamiast tego możemy uzyskać dostęp do wskaźnika do i-tego elementu poprzez:
-1 Ostatni wiersz się nie kompiluje (przynajmniej w VS2017). Kod zakłada, że iterator vector :: jest domyślnie możliwy do zbudowania z surowego wskaźnika, który nie jest wymagany przez standard.
CuriousGeorge
1
Dotyczy to zwłaszcza iteratorów debugowania
Nishant Singh,
9
Jeśli masz nieuporządkowany wektor, możesz skorzystać z faktu, że jest nieuporządkowany i użyć czegoś, co widziałem od Dana Higginsa w CPPCON
Ponieważ kolejność na liście nie ma znaczenia, po prostu weź ostatni element na liście i skopiuj go nad elementem, który chcesz usunąć, a następnie pop i usuń ostatni element.
Myślę, że to najlepsza odpowiedź, jeśli wektor jest nieuporządkowany. Nie opiera się na założeniu, że iterator + indexfaktycznie da ci pozycję iteratora przy tym indeksie, co nie jest prawdą dla wszystkich iterowalnych kontenerów. Jest to również stała złożoność zamiast liniowa dzięki wykorzystaniu tylnego wskaźnika.
theferrit32
1
To całkowicie należy dodać do standardowej biblioteki, ponieważ unordered_removei unordered_remove_if… chyba że tak było i ja tęskniłem, co dzieje się coraz częściej :)
Will Crawford
Jeśli sugeruje użycie przypisania przeniesienia lub zamiany zamiast przypisania kopii.
Carsten S
std::removezmienia kolejność pojemnika, tak aby wszystkie elementy, które mają zostać usunięte, znajdowały się na końcu, nie musisz robić tego ręcznie tak, jeśli używasz C ++ 17.
Keith
@keith jak std::removepomaga? cppreference twierdzi, że nawet w C ++ 17 wszystkie removeprzeciążenia wymagają predykatu i żaden nie przyjmuje indeksu.
Paul Du Bois
4
Jeśli pracujesz z dużymi wektorami (rozmiar> 100 000) i chcesz usunąć wiele elementów, polecam zrobić coś takiego:
int main(int argc,char** argv){
vector <int> vec;
vector <int> vec2;for(int i =0; i <20000000; i++){
vec.push_back(i);}for(int i =0; i < vec.size(); i++){if(vec.at(i)%3!=0)
vec2.push_back(i);}
vec = vec2;
cout << vec.size()<< endl;}
Kod pobiera wszystkie liczby w vec, których nie można podzielić przez 3, i kopiuje je do vec2. Następnie kopiuje vec2 do vec. To jest dość szybkie. Aby przetworzyć 20 000 000 elementów, ten algorytm zajmuje tylko 0,8 sekundy!
Zrobiłem to samo z metodą wymazywania i zajmuje to mnóstwo czasu:
usuniesz n-ty element wektora, ale kiedy usuniesz drugi element, wszystkie inne elementy wektora zostaną przesunięte, a rozmiar wektora wyniesie -1. Może to stanowić problem, jeśli pętla przechodzi przez wektor, ponieważ rozmiar wektora () maleje. Jeśli masz taki problem, podany link sugeruje użycie istniejącego algorytmu w standardowej bibliotece C ++. i „remove” lub „remove_if”.
Poprzednie odpowiedzi zakładają, że zawsze masz podpisany indeks. Niestety, std::vectorużywa size_typedo indeksowania i difference_typearytmetyki iteratora, więc nie działają razem, jeśli masz włączoną opcję „-Wconversion” i znajomych. Jest to kolejny sposób na udzielenie odpowiedzi na pytanie, z możliwością obsługi zarówno podpisanych, jak i niepodpisanych:
Odpowiedzi:
Aby usunąć pojedynczy element, możesz:
Lub, aby usunąć więcej niż jeden element na raz:
źródło
operator+
jest koniecznie zdefiniowane dla iteratorów na innych typach kontenerów, takich jak (nie możesz tego zrobić na , musisz do tego użyć )list<T>::iterator
list.begin() + 2
std::list
std::advance
std::find_if
Metoda kasowania na std :: vector jest przeciążona, więc prawdopodobnie łatwiej jest ją wywołać
gdy chcesz usunąć tylko jeden element.
źródło
vec.begin()
który jest poprawny.vec.erase(0)
to nie działa, alevec.erase(vec.begin()+0)
(lub bez +0) działa. W przeciwnym razie nie otrzymam pasującego wywołania funkcji, dlatego tu przyszedłemvec.erase(0)
może się właściwie skompilować, jeśli0
zostanie zinterpretowane jako stała zerowego wskaźnika ...źródło
template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }
Nie twierdzę, że albo jest lepsza, po prostu pytam z osobistego zainteresowania i zwracam najlepszy wynik, jaki może uzyskać to pytanie.vector<T>::iterator
to iterator o dostępie swobodnym, twoja wersja jest w porządku i może nieco jaśniejsza. Ale wersja, którą opublikował Max, powinna działać dobrze, jeśli zmienisz kontener na inny, który nie obsługuje iteratorów o dostępie swobodnymerase
Sposób zostaną wykorzystane na dwa sposoby:Kasowanie pojedynczego elementu:
Kasowanie zakresu elementów:
źródło
W rzeczywistości
erase
funkcja działa dla dwóch profili:Usuwanie pojedynczego elementu
Usuwanie zakresu elementów
Ponieważ std :: vec.begin () oznacza początek kontenera i jeśli chcemy usunąć ity element z naszego wektora, możemy użyć:
Jeśli przyjrzysz się uważnie, vec.begin () jest tylko wskaźnikiem do pozycji początkowej naszego wektora, a dodanie do niego wartości i zwiększa wskaźnik do pozycji i, więc zamiast tego możemy uzyskać dostęp do wskaźnika do i-tego elementu poprzez:
Więc możemy napisać:
źródło
Jeśli masz nieuporządkowany wektor, możesz skorzystać z faktu, że jest nieuporządkowany i użyć czegoś, co widziałem od Dana Higginsa w CPPCON
Ponieważ kolejność na liście nie ma znaczenia, po prostu weź ostatni element na liście i skopiuj go nad elementem, który chcesz usunąć, a następnie pop i usuń ostatni element.
źródło
iterator + index
faktycznie da ci pozycję iteratora przy tym indeksie, co nie jest prawdą dla wszystkich iterowalnych kontenerów. Jest to również stała złożoność zamiast liniowa dzięki wykorzystaniu tylnego wskaźnika.unordered_remove
iunordered_remove_if
… chyba że tak było i ja tęskniłem, co dzieje się coraz częściej :)std::remove
zmienia kolejność pojemnika, tak aby wszystkie elementy, które mają zostać usunięte, znajdowały się na końcu, nie musisz robić tego ręcznie tak, jeśli używasz C ++ 17.std::remove
pomaga? cppreference twierdzi, że nawet w C ++ 17 wszystkieremove
przeciążenia wymagają predykatu i żaden nie przyjmuje indeksu.Jeśli pracujesz z dużymi wektorami (rozmiar> 100 000) i chcesz usunąć wiele elementów, polecam zrobić coś takiego:
Kod pobiera wszystkie liczby w vec, których nie można podzielić przez 3, i kopiuje je do vec2. Następnie kopiuje vec2 do vec. To jest dość szybkie. Aby przetworzyć 20 000 000 elementów, ten algorytm zajmuje tylko 0,8 sekundy!
Zrobiłem to samo z metodą wymazywania i zajmuje to mnóstwo czasu:
źródło
Aby usunąć element, użyj następującego sposobu:
Aby uzyskać szerszy przegląd , możesz odwiedzić: http://www.cplusplus.com/reference/vector/vector/erase/
źródło
Sugeruję przeczytać to, ponieważ uważam, że tego właśnie szukasz.https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
Jeśli używasz na przykład
usuniesz n-ty element wektora, ale kiedy usuniesz drugi element, wszystkie inne elementy wektora zostaną przesunięte, a rozmiar wektora wyniesie -1. Może to stanowić problem, jeśli pętla przechodzi przez wektor, ponieważ rozmiar wektora () maleje. Jeśli masz taki problem, podany link sugeruje użycie istniejącego algorytmu w standardowej bibliotece C ++. i „remove” lub „remove_if”.
Mam nadzieję, że to pomogło
źródło
Poprzednie odpowiedzi zakładają, że zawsze masz podpisany indeks. Niestety,
std::vector
używasize_type
do indeksowania idifference_type
arytmetyki iteratora, więc nie działają razem, jeśli masz włączoną opcję „-Wconversion” i znajomych. Jest to kolejny sposób na udzielenie odpowiedzi na pytanie, z możliwością obsługi zarówno podpisanych, jak i niepodpisanych:Usuwać:
Brać:
źródło
oto jeszcze jeden sposób, aby to zrobić, jeśli chcesz usunąć element, znajdując go z jego wartością w wektorze, wystarczy to zrobić w wektorze.
usunie twoją wartość stąd. dzięki
źródło
Co powiesz na to?
źródło
najszybszy sposób (dla programowania konkursów według złożoności czasowej () = stała)
może usunąć 100 mln pozycji w ciągu 1 sekundy;
i najbardziej czytelny sposób:
vec.erase(vec.begin() + pos);
źródło
vector<int>::iterator
niekoniecznie jest taki sam jakint *