【问题标题】:How to use .erase() in while loop?如何在while循环中使用.erase()?
【发布时间】:2017-10-21 19:58:06
【问题描述】:

背景: 这是一个将 1 加 1 到存储在向量中的数字的程序。

前面有 0 的数字可以作为输入,但不能作为输出。 eg: 0123 & 123 都是有效输入 但 0124 是无效的输出 而 124 是一个有效的输出

问题: 我想使用erase() 删除输出向量前面的 0,直到使用代码底部的 while 循环找到非零值。 但是编译器返回一个垃圾值。另一个在线编译器给出了分段错误。 其余代码在没有 while 循环的情况下编译时可以正常工作。

#include <iostream>
#include<vector>
using namespace std;
int main()
{
    vector<int> A = { 9, 9, 9 };
    A.insert(A.begin(), 0); /*--last carry may nonzero so new digit -*/
    vector<int>::reverse_iterator it;
    int c = 1;
    for (it = A.rbegin(); it != A.rend(); it++) /*----finds and adds carry---*/
    {
        int d = *it;
        d = d + c;
        c = d / 10;
        if (c == 0)
            *it = d;
        else
        {
            d = d % 10;
            *it = d;
        }

    }
    vector<int>::iterator iss;
    iss = A.begin();

问题循环开始

    while (*iss == 0) /*----------------problem----------------*/
    {
        iss = A.erase(iss);
    }

循环结束

    for (int i = 0; i < A.size(); i++)
    {
        cout << A[i];
    }
}

【问题讨论】:

  • 这个程序对我来说是正确的,并且对我有用。您在粘贴在这里的程序上得到意外的输出或崩溃?你能更具体地谈谈“垃圾价值”吗?
  • 不相关:研究 Erase-remove 成语

标签: c++


【解决方案1】:

你写的几乎是对的。应该对结束迭代器进行额外检查。

while(iss != A.end() && *iss == 0) {
    iss = A.erase(iss);
}

但是,可以实现它,使算法具有更好的性能:

while(iss != A.end() && *iss == 0) {
    ++iss;
}
A.erase(A.begin(), iss);

【讨论】:

  • 一个有用的预防措施,但不能解释给定程序的任何问题,因为它肯定不会有 A 为空或只包含零。
  • @aschepler 让我引用我自己的话:“你写的几乎是正确的。应该对结束迭代器进行额外的检查。”。缺少对结束迭代器的检查是问题所在。如果 A 为空或仅包含零,则我写的任何内容都不存在。但是这些情况也得到了妥善处理。
  • 是的,您的代码总体而言更好更安全。但是在粘贴的程序中while (*iss == 0) { iss = A.erase(); } 不会引起任何问题,因为它原来是A.size() == 4 &amp;&amp; *A.begin() == 1,所以while 循环只做一个有效的取消引用和比较。
  • 同意。一个潜在的错误,但 Asker 提供的代码不会触发它。
  • 您所写的内容以及在 !st for 循环之前放置 A.insert(A.begin() , 0) 解决了问题
【解决方案2】:

不明显你在哪里看到垃圾,但你错过了检查迭代器是否有效,例如while(iss != A.end() &amp;&amp; *iss==0).

【讨论】:

    【解决方案3】:

    与从向量中删除项目相比,几乎总是更可取(从复杂性的角度来看)将要保留的项目移动到另一个向量,将要保留的对象移动到另一个向量。这也有更好的性能(在最好的情况下从向量的头部擦除会移动所有其他对象):

    void remove_zeroes(std::vector<int>& v) {
        std::vector<int> saved;
        auto begin = std::find_if(v.begin(),v.end(),[](int x){ return x != 0; });
        for(auto it = begin; it != v.end(); it++) {
            saved.push_back(std::move(*it));
        }
        v.swap(saved);
    }
    

    虽然在这种情况下,它相当于只使用std::vector 的范围擦除方法,它将两个迭代器作为参数(如其他答案中所建议的那样),如果要删除的元素不在连续范围。

    【讨论】:

      猜你喜欢
      • 2015-04-09
      • 2014-11-01
      • 1970-01-01
      • 2018-02-06
      • 2015-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多