【问题标题】:Unexpected behavior using `std::count` on `std::vector` of pairs在成对的“std::vector”上使用“std::count”的意外行为
【发布时间】:2021-04-14 16:28:43
【问题描述】:

我的目标是完全删除 std::vector<std::pair<int, int>> 中多次出现的所有元素。

这个想法是使用std::remove 和std::count 作为谓词的一部分。我的方法看起来像这样:

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

using std::cout;
using std::endl;
using i_pair = std::pair<int, int>;

int main()
{
    std::vector<i_pair> vec;
    vec.push_back(i_pair(0,0)); // Expected to stay
    vec.push_back(i_pair(0,1)); // Expected to go
    vec.push_back(i_pair(1,1)); // Expected to stay
    vec.push_back(i_pair(0,1)); // Expected to go

    auto predicate = [&](i_pair& p)
    {
        return std::count(vec.begin(), vec.end(), p) > 1;
    };
    auto it = std::remove_if(vec.begin(), vec.end(), predicate);

    cout << "Reordered vector:" << endl;
    for(auto& e : vec)
    {
        cout << e.first << " " << e.second << endl;;
    }
    cout << endl;
    
    cout << "Number of elements that would be erased: " << (vec.end() - it) << endl;

    return 0;
}

数组被重新排序,将两个(0,1) 元素推到末尾,但是std::remove 返回的迭代器指向最后一个元素。这意味着后续的erase 操作只会删除一个(0,1) 元素。

为什么会出现这种情况?如何删除所有多次出现的元素?

【问题讨论】:

    标签: c++ c++11 std stdvector counting


    【解决方案1】:

    您最大的问题是std::remove_if 在向量运行时几乎不能保证向量的内容。

    它保证最后,begin() 到返回的迭代器包含未删除的元素,并且从那里直到end() 还有一些其他元素。

    同时,您正在此操作的中间迭代容器。

    std::partition 更有可能起作用,因为它保证(完成后)您“删除”的元素实际上存储在最后。

    一个更安全的方法是创建一个std::unordered_map&lt;std::pair&lt;int,int&gt;, std::size_t&gt; 并计数一次,然后在第二次通过删除计数至少为 2 的所有内容。这也是 O(n) 而不是您的算法 O(n^ 2) 所以应该更快。

    std::unordered_map<i_pair,std::size_t, pair_hasher> counts;
    counts.reserve(vec.size()); // no more than this
    for (auto&& elem:vec) {
      ++counts[elem];
    }
    vec.erase(std::remove_if(begin(vec), end(vec), [&](auto&&elem){return counts[elem]>1;}), end(vec));
    

    你必须自己写pair_hasher。如果你愿意接受 nlgn 的表现,你可以这样做

    std::map<i_pair,std::size_t> counts;
    for (auto&& elem:vec) {
      ++counts[elem];
    }
    vec.erase(std::remove_if(begin(vec), end(vec), [&](auto&&elem){return counts[elem]>1;}), end(vec));
    

    【讨论】:

    猜你喜欢
    • 2017-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-13
    • 1970-01-01
    • 1970-01-01
    • 2019-05-20
    • 2021-10-01
    相关资源
    最近更新 更多