【问题标题】:Some trouble using erase from vector in C++在 C++ 中使用从向量中擦除的一些问题
【发布时间】:2015-12-04 08:13:59
【问题描述】:

我有一个向量,其中包含 0-14 的随机数,其中一些可能是重复的(例如 {3,8,11,2,3,6,1,11,9,4,13 ,12,6,5,4} 并没有代表所有数字),我想删除重复项并确保代表每个数字 0-14。 所以我还有另一个vector<int> unrepresentedvector<int> duplicates。我用 0-14 的每个数字填充“无代表”:

for (int i = 0; i<num; i++)
{
    unrepresented.push_back(i);
}

然后我执行以下操作:

for (int i = 0; i<num; i++)
{
    if (find(unrepresented.begin(), unrepresented.end(), new_gene_array_one[i]) != new_gene_array_one.end()) 
        unrepresented.erase(i);
    else
        duplicates.push_back(new_gene_array_one[i]);
}

我知道擦​​除函数应该采用迭代器,但我仍然不明白它应该如何使用它,因为我想擦除某个元素(不是位置,而是实际数字) “unrepresented”如果它在那里,否则如果它不在那里,那么把它放在重复向量中,然后在整个事情之后取出未表示向量中的元素并替换原始向量中的重复元素,这样所有的数字将被表示。

【问题讨论】:

  • erase() 采用迭代器。 find() 返回一个迭代器。考虑可能性。

标签: c++ arrays algorithm vector


【解决方案1】:

你需要把find“找到”的迭代器,在erase中使用,否则它就不起作用了。

API 函数的文档记录非常准确,如果你给他们提供他们不期望的东西作为参数,他们就不会做你想做的事。

如果您传递vector::eraseint,它将尝试将其解释为迭代器,因此如果您输入erase(i),它将删除i'th 位置的元素,而不是删除数字列表中的i

【讨论】:

    【解决方案2】:

    可以采取完全不同的方法。在后面再次添加所有数字:

    for (int i = 0; i < num; ++i) {
        new_gene_array_one.push_back(i);
    }
    

    现在所有的数字都被表示出来了,尽管我们可能有重复。使用 set 来记录我们目前看到的那些,并使用 erase-remove 习惯用法来删除重复项:

    std::unordered_set<int> seen;
    new_gene_array_one.erase(
        std::remove_if(new_gene_array_one.begin(),
                       new_gene_array_one.end(),
                       [&](int i) {
                           return !seen.insert(i).second;
                       }),
        new_gene_array_one.end()
    );
    

    unordered_set::insert 表示插入是否成功。如果它成功了,这意味着这是我们第一次看到这个值,所以我们保留它。如果插入失败,这是一个 dup,我们想要删除它 - 所以我们的 remove_if 谓词返回 true;

    【讨论】:

    • 谢谢我最终做了这样的事情。我想我只需要了解一下这个系列。这填补了我想做的事情的空白。
    【解决方案3】:

    迭代器是对容器类中元素的“抽象引用”(在本例中为 std::vector)。您可以通过以下方式更改擦除功能:

    unrepresented.erase(unrepresented.begin() + i);
    

    如果您担心性能问题,这不是一个非常有效的算法,因为 vector 数据结构必须在被删除元素之后移动(通过复制)所有元素,每次擦除函数被调用。有不同的(标准)解决方案可以缓解这个问题,这可能是另一个问题的原因。

    【讨论】:

      【解决方案4】:

      如果您需要以随机顺序排列 0 到 14 之间的数字,我建议您按顺序用 0 到 14 之间的数字填充向量,然后使用 shuffle,例如std::random_shuffle。它很简单,而且是真正随机的:

      vector<int> v = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14};
      //using random shuffle:
      std::random_shuffle(begin(v), end(v));
      

      一般来说,您通常希望使用erase-remove idiomstd::vector 中删除。

      在 OP 的澄清之后,如果 random_shuffle 没有问题,Barry 使用集合的想法是个好建议。在这种情况下,一个有点困难的挑战是确保随机性。如果您只是按建议推回或替换值,您将没有真正的随机性。根据随机性的重要性,或者为什么需要以随机顺序排列这些数字,您可能需要进行额外处理。

      【讨论】:

      • std::shuffle 无疑是最好的解决方案。 std::unique 仅删除 consecutive 重复项,这与 OP 的示例不匹配。
      猜你喜欢
      • 1970-01-01
      • 2018-07-19
      • 1970-01-01
      • 1970-01-01
      • 2019-10-25
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      相关资源
      最近更新 更多