【问题标题】:Count elements in union of two sets using stl使用 stl 计算两个集合中的元素
【发布时间】:2016-06-11 19:09:25
【问题描述】:

我有两个集合,我想知道有多少元素至少在一个集合中。这是<algorithm> 中的一个函数set_union,它将联合写入另一个集合,但我只想要数字。我可以在不保存元素的情况下使用 stl 找到它吗?

【问题讨论】:

  • 我不知道你不计算联合的原因是什么(也许它太贵了?)。或许你可以使用恒等式size(A ∪ B) + size(A ∩ B) = size A + size B。如果你能计算出交集的大小。

标签: c++ stl set


【解决方案1】:

我同意 Marshall Clow 的观点;我不相信有现成的算法可以做到这一点。这是我一直在玩弄的一个想法。它是一个简单的类,提供了一个只增加一个计数器的 push_back 方法。您可以将它与 std::back_inserter 一起用作输出迭代器。

#include <initializer_list>
#include <iterator>
#include <iostream>
#include <algorithm>

template <typename T>
class CountingPushBack
{
  public:
  using value_type = T;

  void push_back(T const &) {++count;}

  std::size_t get_count() const {return count;}

  private:
  std::size_t count = 0;
};

int main()
{
  std::initializer_list<int> il1 = { 0, 1, 2, 3, 4 };
  std::initializer_list<int> il2 = { 0, 2, 4, 6, 8 };

  CountingPushBack<int> cp;

  std::set_union(il1.begin(), il1.end(), 
                 il2.begin(), il2.end(), 
                 std::back_inserter(cp));

  std::cout << cp.get_count() << std::endl;
}

【讨论】:

    【解决方案2】:

    我不知道这样的算法。话虽如此,您可以使用set_union 的胆量编写自己的代码来做到这一点;像这样:

    #include <iostream>
    #include <set>
    
    // Counts the number of elements that would be in the union
    template <class Compare, class InputIterator1, class InputIterator2>
    size_t set_union_size(InputIterator1 first1, InputIterator1 last1,
                          InputIterator2 first2, InputIterator2 last2,
                          Compare comp)
    {
        size_t __result = 0;
        for (; first1 != last1;)
        {
            if (first2 == last2)
                return __result + std::distance(first1, last1);
            if (comp(*first2, *first1))
            {
                ++__result;
                ++first2;
            }
            else
            {
                ++__result;
                if (!comp(*first1, *first2))
                    ++first2;
                ++first1;
            }
        }
        return __result + std::distance(first2, last2);
    }
    
    int main () {
        std::set<int> s1 = { 0, 1, 2, 3, 4 };
        std::set<int> s2 = { 0, 2, 4, 6, 8 };
        std::cout
            << set_union_size(s1.begin(), s1.end(), s2.begin(), s2.end(), std::less<int>())
            << std::endl;
        }
    

    这会打印出7,这是您所期望的。

    【讨论】:

      【解决方案3】:

      虽然 SCFrench 的解决方案很好,但它确实需要一个容器,而我们只需要一个 back_insert_iterator。这是一个实现示例。

      #include <iostream>
      #include <iterator>
      #include <vector>
      #include <algorithm>
      
      template <typename T>
      class count_back_inserter {
          size_t &count;
      public:
          typedef void value_type;
          typedef void difference_type;
          typedef void pointer;
          typedef void reference;
          typedef std::output_iterator_tag iterator_category;
          count_back_inserter(size_t &count) : count(count) {};
          void operator=(const T &){ ++count; }
          count_back_inserter &operator *(){ return *this; }
          count_back_inserter &operator++(){ return *this; }
      };
      

      您可以通过将size_t 变量传递给构造函数来使用它,该变量将为“添加”到“基础容器”的每个元素递增。

      int main(){
          std::vector<int> v1 = {1, 2, 3, 4, 5}; 
          std::vector<int> v2 = {      3, 4, 5, 6, 7}; 
          size_t count = 0;
          set_union(v1.begin(), v1.end(),
                    v2.begin(), v2.end(),
                    count_back_inserter<int>(count));
          std::cout << "The number of elements in the union is " << count << std::endl;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多