Mam std :: vector <int> i chcę usunąć n-ty element. Jak mogę to zrobić?
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
vec.erase(???);
Mam std :: vector <int> i chcę usunąć n-ty element. Jak mogę to zrobić?
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
vec.erase(???);
Odpowiedzi:
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);
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ć
vec.erase(vec.begin() + index);
gdy chcesz usunąć tylko jeden element.
vec.begin()
który jest poprawny.
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
vec.erase(0)
może się właściwie skompilować, jeśli 0
zostanie zinterpretowane jako stała zerowego wskaźnika ...
template <typename T>
void remove(std::vector<T>& vec, size_t pos)
{
std::vector<T>::iterator it = vec.begin();
std::advance(it, pos);
vec.erase(it);
}
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 swobodnym
erase
Sposó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
W rzeczywistości erase
funkcja 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:
&vec[i]
Więc możemy napisać:
vec.erase(&vec[i]); // To delete the ith element
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
template< typename TContainer >
static bool EraseFromUnorderedByIndex( TContainer& inContainer, size_t inIndex )
{
if ( inIndex < inContainer.size() )
{
if ( inIndex != inContainer.size() - 1 )
inContainer[inIndex] = inContainer.back();
inContainer.pop_back();
return true;
}
return false;
}
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.
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
i unordered_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 wszystkie remove
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:
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:
Erase-Version (10k elements) : 0.04 sec
Erase-Version (100k elements) : 0.6 sec
Erase-Version (1000k elements): 56 sec
Erase-Version (10000k elements): ...still calculating (>30 min)
Aby usunąć element, użyj następującego sposobu:
// declaring and assigning array1
std:vector<int> array1 {0,2,3,4};
// erasing the value in the array
array1.erase(array1.begin()+n);
Aby uzyskać szerszy przegląd , możesz odwiedzić: http://www.cplusplus.com/reference/vector/vector/erase/
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
vec.erase(vec.begin() + 1, vec.begin() + 3);
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
Poprzednie odpowiedzi zakładają, że zawsze masz podpisany indeks. Niestety, std::vector
używa size_type
do indeksowania i difference_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ć:
template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
void remove(std::vector<T> &v, I index)
{
const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
v.erase(iter);
}
Brać:
template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
T take(std::vector<T> &v, I index)
{
const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
auto val = *iter;
v.erase(iter);
return val;
}
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.
vector<int> ar(n);
ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));
usunie twoją wartość stąd. dzięki
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;
vector<int> it = (vector<int>::iterator) &vec[pos];
vec.erase(it);
i najbardziej czytelny sposób:
vec.erase(vec.begin() + pos);
vector<int>::iterator
niekoniecznie jest taki sam jakint *