从集合中删除元素的问题

发布于 2024-11-28 15:08:03 字数 1755 浏览 4 评论 0原文

我在从集合中删除元素时遇到麻烦。我得到 BUILD FAILED from:

n2Ar.erase(it);
n3Ar.erase(it);

其中 it 是从 find() 函数接收的指针:例如 it = n2Ar.find(* i);

程序的完整列表:

#include <stdio.h>
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>

using namespace std;

#define TESTING_FILE_IN
//#define TESTING_FILE_OUT
//#define DEBUG
//#define SHOW_TIMING

int outputSet(int i) {
    cout << i << endl;
}

/*
 * 
 */
int main() {

    int n1, n2, n3;
    set<int> list, n1Ar, n2Ar, n3Ar;
    set<int>::iterator it;

    scanf("%d", &n1);
    scanf("%d", &n2);
    scanf("%d", &n3);

    int val = 0;

    // Getting lists of voters
    for (unsigned i = 0; i < n1; i++) {
        cin >> val;
        n1Ar.insert(val);
    }

    for (unsigned i = 0; i < n2; i++) {
        cin >> val;
        n2Ar.insert(val);
    }

    for (unsigned i = 0; i < n3; i++) {
        cin >> val;
        n3Ar.insert(val);
    }

    // Processing lists

    for (set<int>::iterator i = n1Ar.begin(); i != n1Ar.end(); ++i) {
        it = n2Ar.find(*i);

        if (it != n2Ar.end()) {
            list.insert(*i);
            n1Ar.erase(i);
            n2Ar.erase(it);

        } else {

            it = n3Ar.find(*i);
            if (it != n3Ar.end()) {
                list.insert(*i);
                n1Ar.erase(i);
                n3Ar.erase(it);
            }
        }
    }

    // Outputting the final list
    cout << list.size() << endl;
    for_each(list.begin(), list.end(), outputSet);

    return 0;
}

我希望你能够帮助我理解我在这里做错了什么。我只是从 C++ 开始。

I am having troubles with erasing elements from sets. I get BUILD FAILED from:

n2Ar.erase(it);
n3Ar.erase(it);

where it is a pointer received from find() function: e.g. it = n2Ar.find(*i);

The whole listing of the program:

#include <stdio.h>
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>

using namespace std;

#define TESTING_FILE_IN
//#define TESTING_FILE_OUT
//#define DEBUG
//#define SHOW_TIMING

int outputSet(int i) {
    cout << i << endl;
}

/*
 * 
 */
int main() {

    int n1, n2, n3;
    set<int> list, n1Ar, n2Ar, n3Ar;
    set<int>::iterator it;

    scanf("%d", &n1);
    scanf("%d", &n2);
    scanf("%d", &n3);

    int val = 0;

    // Getting lists of voters
    for (unsigned i = 0; i < n1; i++) {
        cin >> val;
        n1Ar.insert(val);
    }

    for (unsigned i = 0; i < n2; i++) {
        cin >> val;
        n2Ar.insert(val);
    }

    for (unsigned i = 0; i < n3; i++) {
        cin >> val;
        n3Ar.insert(val);
    }

    // Processing lists

    for (set<int>::iterator i = n1Ar.begin(); i != n1Ar.end(); ++i) {
        it = n2Ar.find(*i);

        if (it != n2Ar.end()) {
            list.insert(*i);
            n1Ar.erase(i);
            n2Ar.erase(it);

        } else {

            it = n3Ar.find(*i);
            if (it != n3Ar.end()) {
                list.insert(*i);
                n1Ar.erase(i);
                n3Ar.erase(it);
            }
        }
    }

    // Outputting the final list
    cout << list.size() << endl;
    for_each(list.begin(), list.end(), outputSet);

    return 0;
}

I hope you'll be able to help me understand what I am doing wrong in here. I am only starting with C++.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

獨角戲 2024-12-05 15:08:03

您的代码中有两个问题。

首先,您需要在以下函数中返回一个值,或者简单地使其返回 void。

// you should return a value here or make it return void
int outputSet(int i)
{
    cout << i << endl;
}

第二,一旦删除当前迭代器,for 循环的后续迭代中的迭代器就会失效。一旦一个元素被移除,它的迭代器i也失效,从而后续基于++i的迭代器;

你会得到运行时错误,因为迭代器 i 现在指向你需要以某种方式“重置”它。

MSVC 实现

for (set<int>::iterator i = n1Ar.begin(); i != n1Ar.end(); ++i) {
        it = n2Ar.find(*i);

        if (it != n2Ar.end()) {
            list.insert(*i);
            // the following iterators become invalidated after the
            // current one is removed. You need reset it like
            // i = n1Ar.erase(i);
            n1Ar.erase(i);
            n2Ar.erase(it);

        } else {

            it = n3Ar.find(*i);
            if (it != n3Ar.end()) {
                list.insert(*i);
                // the following iterators become invalidated after the
                // current one is removed. You need reset it like
                // i = n1Ar.erase(i);
                n1Ar.erase(i);
                n3Ar.erase(it);
            }
        }
    }

编辑:请注意,从 set::erase() 返回新迭代器不是标准方法。这主要是为了性能的目的。

更便携的解决方案

基本思想是在删除当前迭代器之前正确设置下一个迭代器。

   set<int>::iterator i = n1Ar.begin();

   while (i != n1Ar.end())
   {
      it = n2Ar.find(*i);
      if (it != n2Ar.end())
      {
         // the trick is to use "i++" where i is incremented by one while "old" i
         // is removed.
         list.insert(*i);
         n1Ar.erase(i++);
         n2Ar.erase(it);
      }
      else
      {    
         it = n3Ar.find(*i);
         if (it != n3Ar.end())
         {
            list.insert(*i);
            n1Ar.erase(i++);
            n3Ar.erase(it);
         }
         else
         {
            ++i;
         }
      }
   }

There are two problems in your code.

First, you need return a value in the following function, or simply make it return void.

// you should return a value here or make it return void
int outputSet(int i)
{
    cout << i << endl;
}

Second, the iterators in the following iterations of your for-loop are invalidated once you remove the current one. Once an element is removed, its iterator i is also invalidated, so as to the following iterators based on ++i;

And you'll get run-time error because iterator i now points to You need somehow "reset" it.

MSVC Implementation

for (set<int>::iterator i = n1Ar.begin(); i != n1Ar.end(); ++i) {
        it = n2Ar.find(*i);

        if (it != n2Ar.end()) {
            list.insert(*i);
            // the following iterators become invalidated after the
            // current one is removed. You need reset it like
            // i = n1Ar.erase(i);
            n1Ar.erase(i);
            n2Ar.erase(it);

        } else {

            it = n3Ar.find(*i);
            if (it != n3Ar.end()) {
                list.insert(*i);
                // the following iterators become invalidated after the
                // current one is removed. You need reset it like
                // i = n1Ar.erase(i);
                n1Ar.erase(i);
                n3Ar.erase(it);
            }
        }
    }

Edit: Note that returning a new iterator from set::erase() is not a Standard way. That's mainly for the purpose of performance.

A More Portable Solution

The basic idea is to correctly set the next iterator before removing the current one.

   set<int>::iterator i = n1Ar.begin();

   while (i != n1Ar.end())
   {
      it = n2Ar.find(*i);
      if (it != n2Ar.end())
      {
         // the trick is to use "i++" where i is incremented by one while "old" i
         // is removed.
         list.insert(*i);
         n1Ar.erase(i++);
         n2Ar.erase(it);
      }
      else
      {    
         it = n3Ar.find(*i);
         if (it != n3Ar.end())
         {
            list.insert(*i);
            n1Ar.erase(i++);
            n3Ar.erase(it);
         }
         else
         {
            ++i;
         }
      }
   }
鸢与 2024-12-05 15:08:03
n1Ar.erase(i);

std::set::erase 函数使迭代器 i 无效并导致问题。考虑更改以下内容:

for (set<int>::iterator i = n1Ar.begin(); i != n1Ar.end(); ++i) {
        it = n2Ar.find(*i);

        if (it != n2Ar.end()) {
            list.insert(*i);
            i = n1Ar.erase(i);
            if(i == n1Ar.cend())
                break;
            n2Ar.erase(it);

        } else {

if(i == n1Ar.cend()) break; 检查有助于确保无效的迭代器不会破坏循环。

n1Ar.erase(i);

The std::set::erase function invalidates the iterator i and causes the problem. Consider change to the following:

for (set<int>::iterator i = n1Ar.begin(); i != n1Ar.end(); ++i) {
        it = n2Ar.find(*i);

        if (it != n2Ar.end()) {
            list.insert(*i);
            i = n1Ar.erase(i);
            if(i == n1Ar.cend())
                break;
            n2Ar.erase(it);

        } else {

The if(i == n1Ar.cend()) break; check helps to ensure the invalidated iterator will not ruin the loop.

孤独岁月 2024-12-05 15:08:03
  1. Erase 方法使迭代器 i 无效。
  2. Erase 方法不返回迭代器。

编辑:重复埃里克的想法,您可以使用以下代码:

for (set<int>::iterator i = n1Ar.begin(); i != n1Ar.end(); )
    if ( n2Ar.erase(*i) || n3Ar.erase(*i) ) {
        list.insert(*i);
        n1Ar.erase(i++);
    } else i++;

此外,这个问题可以使用标准算法来解决。但这个解决方案似乎效率较低:

set<int> tmp;
std::set_union( n2Ar.begin(), n2Ar.end(),
    n3Ar.begin(), n3Ar.end(), std::inserter(tmp,tmp.begin()) );
std::set_intersection( n1Ar.begin(), n1Ar.end(),
    tmp.begin(), tmp.end(), std::inserter(list,list.begin()) );

最后我建议使用 stl 进行输出(您必须包含迭代器库):

std::copy( list.begin(), list.end(), std::ostream_iterator<int>(std::cout,"\n"));
  1. Erase method invalidates the iterator i.
  2. Erase method does not return iterator.

EDIT: repeating Eric idea you can use the following code:

for (set<int>::iterator i = n1Ar.begin(); i != n1Ar.end(); )
    if ( n2Ar.erase(*i) || n3Ar.erase(*i) ) {
        list.insert(*i);
        n1Ar.erase(i++);
    } else i++;

Also this problem could be solved using standard algorithms. But this solution seems to be less efficient:

set<int> tmp;
std::set_union( n2Ar.begin(), n2Ar.end(),
    n3Ar.begin(), n3Ar.end(), std::inserter(tmp,tmp.begin()) );
std::set_intersection( n1Ar.begin(), n1Ar.end(),
    tmp.begin(), tmp.end(), std::inserter(list,list.begin()) );

Finally i suggest to use stl for your output (you have to include iterator library):

std::copy( list.begin(), list.end(), std::ostream_iterator<int>(std::cout,"\n"));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文