【问题标题】:Vector erase function not working (simple code) [duplicate]矢量擦除功能不起作用(简单代码)[重复]
【发布时间】:2014-10-17 04:40:48
【问题描述】:

谁能解释一下为什么这段代码没有从向量中删除所有的 1:

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

【问题讨论】:

  • 使用std::remove。另请参阅擦除删除习语及其存在的原因。
  • 会检查一下,谢谢。
  • 好的,所以我按照 chris 的建议使用了擦除删除习语,这是我得到的代码:numbers.erase(remove(numbers.begin(), numbers.end(), i), numbers.end());,我从 IntelliSense 收到错误:Error 2 error C2660: 'remove' : function does not take 3 arguments。我做错了什么?
  • @user3650284,您没有包含&lt;algorithm&gt;
  • 确定要使用i?它应该只是替换您的循环并使用 1.

标签: c++


【解决方案1】:

让我们试试吧。

假设你有一个向量,其内容为[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,因此您跳过了一个元素而没有查看它。

【讨论】:

  • 感谢您的分析,这让我更清楚了。是否有可能以某种方式使用for (int x : numbers) 删除 x 元素?
  • 常规方法是“擦除/删除习语”。这个想法是在迭代器范围numbers.begin(), numbers.end() 上使用std::remove 来删除所有要删除的元素。这将返回一个指向“未删除”序列末尾的新迭代器。然后将该迭代器和numbers.end() 传递给numbers.erase 以从向量中擦除清理序列结束和向量结束之间的所有内容
【解决方案2】:

你的代码说 i

如果 numbers[]={0,1,2,3,1,4} -> 你会得到 numbers[]={0,2,3,4}强>

如果 numbers[]={0,1,1,2,3,1,4} -> 你得到 numbers[]={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--; } } 这会给你正确的答案。

【讨论】:

  • 这也可以,我明白了。谢谢你的想法。
【解决方案3】:

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

有效循环可能如下所示

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

考虑到应用标头&lt;algorithm&gt;中声明的标准算法std::remove更简单

例如

#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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多