矢量擦除功能不起作用(简单代码)

时间:2014-08-23 12:44:03

标签: c++

有人可以解释一下为什么这段代码不会从矢量中删除所有1:

for (int i = 0; i < numbers.size(); i++)
{
    if (numbers[i] == 1)
    {
        numbers.erase(numbers.begin() + i);
    }
}

3 个答案:

答案 0 :(得分:4)

我们试一试。

假设你有一个内容为[1, 1, 1]的向量(所有这些,只是为了保持简单)

第一次迭代:

for (int i = 0; i < numbers.size(); i++) <-- i == 0; numbers.size() == 3
{
    if (numbers[i] == 1) <-- true
    {
        numbers.erase(numbers.begin() + i); <-- erase is called on element #0
    }
}

第二次迭代: 该向量现在包含[1, 1],因为我们删除了第0个条目。

for (int i = 0; i < numbers.size(); i++) <-- i == 1; numbers.size() == 2
{
    if (numbers[i] == 1) <-- true
    {
        numbers.erase(numbers.begin() + i); <-- erase is called on element #1
    }
}

第三次迭代: 该向量现在包含[1]

for (int i = 0; i < numbers.size(); i++) <-- i == 2; numbers.size() == 1; the loop condition is false, so we exit the loop
{
    if (numbers[i] == 1)
    {
        numbers.erase(numbers.begin() + i);
    }
}

最终结果:

向量包含[1]

正如您可以通过手动逐行评估代码看到的那样,问题是即使在删除元素后也会增加i。每次删除一个元素时,都会将所有剩余的元素移动到较低的索引,但同时增加计数器,以便您查看的下一个索引高一个。因此,当您删除元素i时,先前索引为i+1的元素将移至索引i。但是在下一次迭代中,您不再查看索引i,而是查看i+1,因此您跳过一个元素而不查看它。

答案 1 :(得分:2)

你的代码说 我&lt; numbers.size(),你递增i并删除n [i](如果它有1) 删除后,你不应该增加i,因为一个新的数字在i的当前位置。

如果数字[] = {0,1,2,3,1,4} - >你得到数字[] = {0,2,3,4}

如果数字[] = {0,1,1,2,3,1,4} - >你得到数字[] = {0,1,2,3,4}

即删除后,它会跳过下一个号码 只需添加i--;删除数字后[i]

for (int i = 0; i < numbers.size(); i++){ if (numbers[i] == 1){ numbers.erase(numbers.begin() + i); i--; } } 这将给你正确的答案。

答案 2 :(得分:1)

当擦除向量的元素时,擦除元素之后的所有元素都向左移动。因此,例如,如果删除了索引为0的元素,那么向量的第一个实际元素将具有等于9的索引。在这种情况下,不得增加索引。

有效循环可能看起来像

for ( int i = 0; i < numbers.size(); )
{
    if ( numbers[i] == 1 )
    {
        numbers.erase( numbers.begin() + i );
    }
    else
    {
        ++i;
    }
}

考虑到应用标题std::remove中声明的标准算法<algorithm>更简单

例如

#include <algorithm>

//...

numbers.erase( std::remove( numbers.begin(), numbers.end(), 1 ), numbers.end() );

这是一个示范性的例子

#include <iostream>
#include <vector>
#include <algorithm>

int main() 
{
    std::vector<int> v = { 1, 1, 2, 1, 3, 1, 4, 1, 5 };

    for ( int x : v ) std::cout << x << ' ';
    std::cout << std::endl;

    v.erase( std::remove( v.begin(), v.end(), 1 ), v.end() );

    for ( int x : v ) std::cout << x << ' ';
    std::cout << std::endl;

    return 0;
}

输出

1 1 2 1 3 1 4 1 5 
2 3 4 5