【问题标题】:Keeping values of vector [duplicate]保持向量的值[重复]
【发布时间】:2020-06-03 18:43:10
【问题描述】:

我在编写一个只保留重复项的程序时遇到了麻烦,这是我已经写过的:

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


int main()
{
    std::vector<int> v;

    for (int n; std::cin >> n;) 
    {v.push_back(n); }
    std::sort(v.begin(),v.end());

    for(std::vector<int>::iterator b = v.begin();b<v.end();++b)
    {

        if(*b != *(b+1) )
        {
            v.erase(b);


        }

    }

    for(std::vector<int>::iterator i = v.begin();i < v.end();++i)
    {
        std::cout<<*i<<" ";
    }


}

我所说的“保持重复”的意思是例如
Input: 13 7 2 13 5 2 1 13 Output : 2 13 如果代码不是那么完美,我很抱歉,我完全是初学者。希望你能理解我的困难。

【问题讨论】:

  • 迭代器失效的经典案例。最好的办法是从向量的末尾一直工作到开头。
  • 你的意思是,切换开始和结束?
  • 老兄,你认为取出后剩下的元素会发生什么?他们都移回了一个地方。所以++b 会做坏事。
  • 你需要把你的调试器拿出来自己看看。 3小时不算什么。 3年是博士学位。
  • @Theooc 尝试使用它而不是您正在擦除元素的循环。 auto last = v.begin(); for (auto b = v.begin(); b &lt; v.end() - 1; ++b) if (*b == *(b + 1) &amp;&amp; (*b == *last || *b != *(last - 1))) *last++ = *b; v.erase(last, v.end());Here is full code.

标签: c++


【解决方案1】:

当您从vectorerase() 时,所有指向已擦除元素的迭代器或vector 之后的所有迭代器都将失效。幸运的是,erase() 将迭代器返回到被擦除元素之后的元素,所以你可以这样做:

for(auto b = v.begin(), end=std::prev(v.end()); b != end;) {
    if(*b != *(b+1) ) b = v.erase(b);
    else              ++b;
}

请注意,您需要在end() 之前停止迭代一个元素之前,因为您这样做了*(b+1)

但上述内容并未删除所有重复元素,只删除一个

另一种方法是搜索不属于重复序列的第一个元素,如果没有重复则删除该元素,如果有重复则删除所有重复,但只有一个。

我在下面的示例中使用了标准算法std::find_if_not,但您可以轻松地将其替换为执行相同操作的循环。只需搜索第一个元素等于*b

#include <algorithm>

for(auto b = v.begin(); b != v.end();) {

    // find the first element not being a repetition of *b
    auto r = std::find_if_not(b + 1, v.end(), [&b](const auto& v) { return *b==v; });

    if(b + 1 == r) b = v.erase(b);        // *b had no repetitions, erase b
    else           b = v.erase(b + 1, r); // erase all repetitions except one element
}

【讨论】:

    【解决方案2】:

    您正在尝试取消引用无效的迭代器。在第二个 for 循环的最后一次迭代中,*(b+1) 将尝试取消引用此迭代器。 变化:

    for(std::vector<int>::iterator b = v.begin();b<v.end();++b)
    

    到:

    for(std::vector<int>::iterator b = v.begin();b<v.end()-1;++b)
    
    

    并将您的擦除更改为:

    v.erase(b+1)
    

    您正在尝试擦除当前迭代中的迭代器。

    【讨论】:

    • 对循环中发生的v.erase(b);有何评论?
    • 如果您要指出这一点,您可能应该建议使用基于范围的 for 循环。
    • &lt; 用于迭代器是非常不寻常的
    • 我可能做错了,但这个算法还是有问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-21
    • 2017-08-01
    • 2018-02-08
    • 2017-09-18
    • 2021-09-09
    • 2020-03-25
    • 2015-07-03
    相关资源
    最近更新 更多