C ++:2个数组之间的差异

时间:2014-08-21 15:20:52

标签: c++ c++11 set

我有两个单个简单元素类型的未分类随机访问数组(int / string / etc,因此所有比较运算符都可以进行哈希处理等)。任何一个数组都不应该有重复的元素。

寻找给出这些数组A和B的一般算法告诉我:

  1. A和B中包含哪些元素
  2. A中有哪些元素但不是B
  3. B中有哪些元素但不是A
  4. 我想我可以使用如下的集合运算符执行此操作,但是有更快的解决方案(例如,不需要我构建两个有序集合)吗?

    r1 = std::set_intersection(a,b);
    r2 = std::set_difference(a,b);
    r3 = std::set_difference(b,a);
    

3 个答案:

答案 0 :(得分:3)

类似下面的算法将运行O(| A | + | B |)(假设来自unordered_map的O(1)行为):

  • 让列表onlyA最初包含所有A,列表onlyBbothAB开头为空。
  • 让哈希表AmaponlyA中的元素与onlyA中对应的迭代器相关联。
  • B中的每个元素 b
    • 如果 b 在Amap中找到相应的迭代器 ai
      • b 添加到bothAB
      • 使用 ai
      • onlyA删除 b
    • 否则,请将 b 添加到onlyB

在上述算法结束时,

  • onlyA包含A中的元素但不包含B,
  • onlyB包含B中的元素但不包含A,
  • 两个AB都包含A和B中的元素。

以下是上述的实现。结果以元组< onlyAonlyBbothAB>返回。

template <typename C>
auto venn_ify (const C &A, const C &B) ->
    std::tuple<
        std::list<typename C::value_type>,
        std::list<typename C::value_type>,
        std::list<typename C::value_type>
    >
{
    typedef typename C::value_type T;
    typedef std::list<T> LIST;
    LIST onlyA(A.begin(), A.end()), onlyB, bothAB;
    std::unordered_map<T, typename LIST::iterator> Amap(2*A.size());
    for (auto a = onlyA.begin(); a != onlyA.end(); ++a) Amap[*a] = a;
    for (auto b : B) {
        auto ai = Amap.find(b);
        if (ai == Amap.end()) onlyB.push_back(b);
        else {
            bothAB.push_back(b);
            onlyA.erase(ai->second);
        }
    }
    return std::make_tuple(onlyA, onlyB, bothAB);
}

答案 1 :(得分:3)

首先,你的问题不清楚你的意思 std::set当你谈到排序集时。如果是这样,那么你的 第一反应应该是使用std::vector,如果可以的话 原始载体。只需对它们进行排序,然后:

std::vector<T> r1;
std::set_intersection( a.cbegin(), a.cend(), b.cbegin(), b.cend(), std::back_inserter( r1 ) );

r2r3也是如此。

除此之外,我怀疑你能做多少事情。只有一个 循环可能会改善一些事情:

std::sort( a.begin(), a.end() );
std::sort( b.begin(), b.end() );
onlyA.reserve( a.size() );
onlyB.reserve( b.size() );
both.reserve( std::min( a.size(), b.size() ) );
auto ita = a.cbegin();
auto enda = a.cend();
auto itb = b.cbegin();
auto endb = b.cend();
while ( ita != enda && itb != endb ) {
    if ( *ita < *itb ) {
        onlyA.push_back( *ita );
        ++ ita;
    } else if ( *itb < *ita ) {
        onlyB.push_back( *itb );
        ++ itb;
    } else {
        both.push_back( *ita );
        ++ ita;
        ++ itb;
    }
}
onlyA.insert( onlyA.end(), ita, enda );
onlyB.insert( onlyB.end(), itb, endb );

reserve可能会有所作为,除非大多数人都这样做 元素最终在同一个向量中,可能不会花费太多 额外的记忆。

答案 2 :(得分:-1)

您可以通过将A的元素放入unordered_map(其中A中的元素是键)来以线性时间执行此操作。检查地图中键中B的元素。