Chcę usunąć element z wektora za pomocą metody wymazywania. Ale problem polega na tym, że nie ma gwarancji, że element wystąpi tylko raz w wektorze. Może występować wiele razy i muszę je wszystkie usunąć. Mój kod wygląda mniej więcej tak:
void erase(std::vector<int>& myNumbers_in, int number_in)
{
std::vector<int>::iterator iter = myNumbers_in.begin();
std::vector<int>::iterator endIter = myNumbers_in.end();
for(; iter != endIter; ++iter)
{
if(*iter == number_in)
{
myNumbers_in.erase(iter);
}
}
}
int main(int argc, char* argv[])
{
std::vector<int> myNmbers;
for(int i = 0; i < 2; ++i)
{
myNmbers.push_back(i);
myNmbers.push_back(i);
}
erase(myNmbers, 1);
return 0;
}
Ten kod oczywiście ulega awarii, ponieważ podczas iteracji zmieniam koniec wektora. Jaki jest najlepszy sposób, aby to osiągnąć? Czy jest jakiś sposób, aby to zrobić bez wielokrotnego iterowania wektora lub tworzenia jeszcze jednej kopii wektora?
std::remove()
przesuwa elementy w taki sposób, że elementy do usunięcia są nadpisywane. Algorytm nie zmienia rozmiaru kontenera, a jeślin
elementy zostaną usunięte, nie jest zdefiniowane, jakie są ostatnien
elementy.Wywołanie kasowania unieważni iteratory, możesz użyć:
Lub możesz użyć std :: remove_if razem z funktorem i std :: vector :: erase:
Zamiast pisać własny funktor w tym przypadku możesz użyć std :: remove :
W C ++ 11 zamiast funktora można by użyć lambdy:
W C ++ 17 dostępne są również std :: experimental :: erase i std :: experimental :: erase_if , w C ++ 20 są one (ostatecznie) przemianowane na std :: erase i std :: erase_if :
lub:
źródło
erase
pomocąremove
jest kanonicznym sposobem na zrobienie tego.Możesz iterować używając dostępu do indeksu,
Aby uniknąć złożoności O (n ^ 2), możesz użyć dwóch indeksów, i - bieżącego indeksu testowego, j - indeksu do przechowywania następnego elementu i na koniec cyklu nowego rozmiaru wektora.
kod:
W takim przypadku nie masz unieważniania iteratorów, złożoność wynosi O (n), a kod jest bardzo zwięzły i nie musisz pisać niektórych klas pomocniczych, chociaż w niektórych przypadkach użycie klas pomocniczych może przynieść korzyści w bardziej elastycznym kodzie.
Ten kod nie używa
erase
metody, ale rozwiązuje twoje zadanie.Używając czystego stl możesz to zrobić w następujący sposób (jest to podobne do odpowiedzi Mottiego):
źródło
W zależności od tego, dlaczego to robisz, używając std :: set może być lepszym pomysłem niż std :: vector.
Dzięki temu każdy element występuje tylko raz. Jeśli dodasz go wiele razy, i tak będzie tylko jedno wystąpienie do usunięcia. To sprawi, że operacja wymazywania będzie banalna. Operacja wymazywania będzie również miała mniejszą złożoność czasową niż na wektorze, jednak dodawanie elementów na planie jest wolniejsze, więc może nie być zbyt korzystne.
To oczywiście nie zadziała, jeśli interesuje Cię, ile razy element został dodany do twojego wektora lub kolejność dodawania elementów.
źródło
Aby usunąć pierwszy element, możesz użyć:
źródło