Я хочу удалить элемент из вектора с помощью метода стирания. Но проблема здесь в том, что элемент не обязательно встречается в векторе только один раз. Он может присутствовать несколько раз, и мне нужно удалить их все. Мой код выглядит примерно так:
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;
}
Этот код, очевидно, дает сбой, потому что я изменяю конец вектора во время итерации по нему. Как лучше всего этого добиться? Т.е. есть ли способ сделать это без многократной итерации вектора или создания еще одной копии вектора?
std::remove()
сдвигает элементы таким образом, что удаляемые элементы перезаписываются. Алгоритм не изменяет размер контейнера, и еслиn
элементы удаляются, то не определено, какиеn
элементы будут последними .Вызов стирания аннулирует итераторы, вы можете использовать:
Или вы можете использовать std :: remove_if вместе с функтором и std :: vector :: erase:
Вместо написания собственного функтора в этом случае вы можете использовать std :: remove :
В С ++ 11 вы можете использовать лямбда вместо функтора:
В C ++ 17 станд :: экспериментальный :: Стирание и станд :: экспериментальный :: erase_if также доступны, в C ++ 20 это (наконец) переименовали в станд :: Стирание и станд :: erase_if :
или:
источник
erase
с помощьюremove
- канонический способ сделать это.Вы можете выполнять итерацию, используя доступ к индексу,
Чтобы избежать сложности O (n ^ 2), вы можете использовать два индекса: i - текущий индекс тестирования, j - индекс для хранения следующего элемента и в конце цикла новый размер вектора.
код:
В таком случае у вас нет аннулирования итераторов, сложность O (n), код очень лаконичный, и вам не нужно писать некоторые вспомогательные классы, хотя в некоторых случаях использование вспомогательных классов может принести пользу в более гибком коде.
Этот код не использует
erase
метод, но решает вашу задачу.Используя чистый stl, вы можете сделать это следующим образом (это похоже на ответ Мотти):
источник
В зависимости от того, почему вы это делаете, использование std :: set может быть лучше, чем std :: vector.
Это позволяет каждому элементу встречаться только один раз. Если вы добавите его несколько раз, в любом случае будет удален только один экземпляр. Это сделает операцию стирания тривиальной. Операция стирания также будет иметь меньшую временную сложность, чем в векторе, однако добавление элементов в набор происходит медленнее, поэтому это не может быть большим преимуществом.
Это, конечно, не сработает, если вас интересует, сколько раз элемент был добавлен в ваш вектор или порядок добавления элементов.
источник
Чтобы стереть 1-й элемент, вы можете использовать:
источник