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

C++: Differences between 2 arrays

本文关键字:之间 数组 C++      更新时间:2023-10-16

我有两个单一简单元素类型的未排序随机访问数组(int/string/etc,所以有所有的比较运算符,可以散列等(。两个数组中都不应有重复的元素。

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

  1. A 和 B 中都有哪些元素
  2. 哪些元素在 A 中,而不是 B 中
  3. 哪些元素在 B 中,而不是 A 中

我想我可以使用下面的集合运算符来做到这一点,但是有没有更快的解决方案(例如,不需要我构建两个排序集的解决方案(?

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

首先,从你的问题中不清楚你的意思是 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可能会有所作为,除非大多数元素最终位于同一个向量中,可能不会花费太多额外内存。

类似于以下算法的内容将运行 O(|A|+|B|((假设 O(1( 行为来自 unordered_map(:

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

在上述算法的最后,

    只有 A 包含
  • A 中的元素,但不包含 B 中的元素,
  • 只有 B 包含 B 中的元素,但在 A 中不包含元素,
  • bothAB 都包含 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);
}

您可以通过将 A 的元素放入 A 中的元素作为键的unordered_map中来线性时间执行此操作。 检查映射中键中 B 的元素是否。