지우기 방법을 사용하여 벡터에서 요소를 지우고 싶습니다. 그러나 여기서 문제는 요소가 벡터에서 한 번만 발생한다는 보장이 없다는 것입니다. 여러 번 나타날 수 있으며 모두 지워야합니다. 내 코드는 다음과 같습니다.
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::vector<int>& vec = myNumbers; // use shorter name
vec.erase(std::remove(vec.begin(), vec.end(), number_in), vec.end());
의 시작 부분에서 remove
제거 할 값 ( number_in
) 과 다른 요소 를 압축하고 vector
해당 범위 이후의 첫 번째 요소에 반복자를 반환합니다. 그런 다음 erase
이러한 요소 (값이 지정되지 않음)를 제거합니다.
답변
erase를 호출하면 반복기가 무효화되며 다음을 사용할 수 있습니다.
void erase(std::vector<int>& myNumbers_in, int number_in)
{
std::vector<int>::iterator iter = myNumbers_in.begin();
while (iter != myNumbers_in.end())
{
if (*iter == number_in)
{
iter = myNumbers_in.erase(iter);
}
else
{
++iter;
}
}
}
또는 std :: remove_if를 functor 및 std :: vector :: erase와 함께 사용할 수 있습니다 .
struct Eraser
{
Eraser(int number_in) : number_in(number_in) {}
int number_in;
bool operator()(int i) const
{
return i == number_in;
}
};
std::vector<int> myNumbers;
myNumbers.erase(std::remove_if(myNumbers.begin(), myNumbers.end(), Eraser(number_in)), myNumbers.end());
이 경우 자체 functor를 작성하는 대신 std :: remove 사용할 수 있습니다 .
std::vector<int> myNumbers;
myNumbers.erase(std::remove(myNumbers.begin(), myNumbers.end(), number_in), myNumbers.end());
C ++ 11에서는 functor 대신 lambda를 사용할 수 있습니다.
std::vector<int> myNumbers;
myNumbers.erase(std::remove_if(myNumbers.begin(), myNumbers.end(), [number_in](int number){ return number == number_in; }), myNumbers.end());
C ++ 17에서는 std :: experimental :: erase 및 std :: experimental :: erase_if 도 사용할 수 있으며, C ++ 20에서는 (마지막으로) std :: erase 및 std :: erase_if 로 이름이 변경되었습니다 .
std::vector<int> myNumbers;
std::erase_if(myNumbers, Eraser(number_in)); // or use lambda
또는:
std::vector<int> myNumbers;
std::erase(myNumbers, number_in);
답변
-
인덱스 액세스를 사용하여 반복 할 수 있습니다.
-
O (n ^ 2) 복잡성을 피하기 위해 두 개의 인덱스, i-현재 테스트 인덱스, j-인덱스를 사용하여 다음 항목을 저장하고주기가 끝날 때 벡터의 새 크기를 사용할 수 있습니다.
암호:
void erase(std::vector<int>& v, int num)
{
size_t j = 0;
for (size_t i = 0; i < v.size(); ++i) {
if (v[i] != num) v[j++] = v[i];
}
// trim vector to new size
v.resize(j);
}
이 경우 반복자를 무효화하지 않고 복잡성은 O (n)이며 코드는 매우 간결하며 일부 도우미 클래스를 작성할 필요가 없습니다.
이 코드는 erase
방법을 사용하지 않지만 작업을 해결합니다.
pure stl을 사용하면 다음과 같은 방식으로이를 수행 할 수 있습니다 (이는 Motti의 답변과 유사합니다).
#include <algorithm>
void erase(std::vector<int>& v, int num) {
vector<int>::iterator it = remove(v.begin(), v.end(), num);
v.erase(it, v.end());
}
답변
이 작업을 수행하는 이유에 따라 std :: set을 사용하는 것이 std :: vector보다 더 나은 아이디어 일 수 있습니다.
각 요소가 한 번만 발생할 수 있습니다. 여러 번 추가하면 어쨌든 지울 인스턴스가 하나만 있습니다. 이렇게하면 지우기 작업이 간단 해집니다. 지우기 작업은 벡터보다 시간 복잡도가 낮지 만 세트에서 요소를 추가하는 것이 더 느리므로 그다지 이점이 없을 수 있습니다.
물론 요소가 벡터에 추가 된 횟수 또는 요소가 추가 된 순서에 관심이있는 경우에는 작동하지 않습니다.
답변
첫 번째 요소를 지우려면 다음을 사용할 수 있습니다.
vector<int> mV{ 1, 2, 3, 4, 5 };
vector<int>::iterator it;
it = mV.begin();
mV.erase(it);