是否可以在一行中找到 c++ 中 3 个集合的交集?

时间:2020-12-19 07:07:37

标签: c++ stl set

我有 3 套 A、B、C。我需要找到 联合(交集(A,B),交集(B,C),交集(A,C))

(A ∩ B) ∪ (B ∩ C) ∪ (A ∩ C) 集合表示法。

是否可以将其转换为代码而无需再声明 4 个集合。

#include <set> 
using namespace std;
set<int> set1, set2, set3;
set1.insert(1);
set1.insert(2);
set2.insert(2);
set2.insert(3);
set3.insert(1);
set3.insert(4);
// set1 = {1,2} , set2 = {2,3}, set3 = {1,4}


这里是使用 set_intersection() 和 set_union() 的正常方法

set<int> res1, res2,res3;
set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), inserter(res1,res1.begin()));
set_intersection(set2.begin(), set2.end(), set3.begin(), set3.end(), inserter(res2,res2.begin()));
set_intersection(set1.begin(), set1.end(), set3.begin(), set3.end(), inserter(res3,res3.begin()));
set<int> result;
set_union(res1.begin(), res1.end(), res2.begin(), res2.end(), inserter(result, result.begin())
.
.
.

我想知道是否有更优雅的方法来代替。有人能给我一些建议吗?

2 个答案:

答案 0 :(得分:1)

你可以,但这会是一个非常长的行,会惹怒任何试图阅读它的人。

至于更“优雅”的方法,您应该将您想要做的事情拆分成函数:

    vector <int> getIntersection(vector < vector <int> > &sets) 
{ 
    vector <int> result;  // To store the reaultant set 
    int smallSetInd = 0;  // Initialize index of smallest set 
    int minSize = sets[0].size(); // Initialize size of smallest set 
  
    // sort all the sets, and also find the smallest set 
    for (int i = 1 ; i < sets.size() ; i++) 
    { 
        // sort this set 
        sort(sets[i].begin(), sets[i].end()); 
  
        // update minSize, if needed 
        if (minSize > sets[i].size()) 
        { 
            minSize = sets[i].size(); 
            smallSetInd = i; 
        } 
    } 
  
    map<int,int> elementsMap; 
  
    // Add all the elements of smallest set to a map, if already present, 
    // update the frequency 
    for (int i = 0; i < sets[smallSetInd].size(); i++) 
    { 
        if (elementsMap.find( sets[smallSetInd][i] ) == elementsMap.end()) 
            elementsMap[ sets[smallSetInd][i] ] = 1; 
        else
            elementsMap[ sets[smallSetInd][i] ]++; 
    } 
  
    // iterate through the map elements to see if they are present in 
    // remaining sets 
    map<int,int>::iterator it; 
    for (it = elementsMap.begin(); it != elementsMap.end(); ++it) 
    { 
        int elem = it->first; 
        int freq = it->second; 
  
        bool bFound = true; 
  
        // Iterate through all sets 
        for (int j = 0 ; j < sets.size() ; j++) 
        { 
            // If this set is not the smallest set, then do binary search in it 
            if (j != smallSetInd) 
            { 
                // If the element is found in this set, then find its frequency 
                if (binary_search( sets[j].begin(), sets[j].end(), elem )) 
                { 
                   int lInd = lower_bound(sets[j].begin(), sets[j].end(), elem) 
                                                            - sets[j].begin(); 
                   int rInd = upper_bound(sets[j].begin(), sets[j].end(), elem) 
                                                            - sets[j].begin(); 
  
                   // Update the minimum frequency, if needed 
                   if ((rInd - lInd) < freq) 
                       freq = rInd - lInd; 
                } 
                // If the element is not present in any set, then no need  
                // to proceed for this element. 
                else
                { 
                    bFound = false; 
                    break; 
                } 
            } 
        } 
  
        // If element was found in all sets, then add it to result 'freq' times 
        if (bFound) 
        { 
            for (int k = 0; k < freq; k++) 
                result.push_back(elem); 
        } 
    } 
    return result; 
} 

然后在您的主干道(或您需要到达路口的任何地方)执行以下操作:

vector < vector <int> > sets; 
    vector <int> set1; 
    set1.push_back(1); 
    set1.push_back(1); 
    set1.push_back(2); 
    set1.push_back(2); 
    set1.push_back(5); 
  
    sets.push_back(set1); 
  
    vector <int> set2; 
    set2.push_back(1); 
    set2.push_back(1); 
    set2.push_back(4); 
    set2.push_back(3); 
    set2.push_back(5); 
    set2.push_back(9); 
  
    sets.push_back(set2); 
  
    vector <int> set3; 
    set3.push_back(1); 
    set3.push_back(1); 
    set3.push_back(2); 
    set3.push_back(3); 
    set3.push_back(5); 
    set3.push_back(6); 
  
    sets.push_back(set3); 
  
    vector <int> r = getIntersection(sets); 

现在你有了一个你输入的集合之间的交集向量。它可以是 3,也可以是 30,000,等等。

答案 1 :(得分:0)

要获得集合的所有交集的并集,看起来您只需要获取出现在两个或多个集合中的所有值。交集是两个集合包含相同值的地方,联合是出现在“两个”集合中的所有值的集合。因此,所有可能的交集的联合将包括出现在至少两个集合中的任何值

例如,对于集合 {1, 2}{2, 3}{1, 4},所有交集的并集将为 {1, 2}

这应该适用于任意数量的集合。

#include <iostream>
#include <unordered_map>
#include <set>
#include <vector>

std::set<int> unionOfIntersections(const std::vector<const std::set<int>*>& sets) {
  std::unordered_map<int, int> flattened_value_count_map;

  for (const auto& set : sets) {
    for (const int num : *set) {
      auto overlaps_iter = flattened_value_count_map.find(num);

      // Count the number of times each value occurs, for every set
      if (overlaps_iter == flattened_value_count_map.end()) {
        flattened_value_count_map[num] = 1;
      }
      else {
        ++overlaps_iter->second;
      }
    }
  }

  std::set<int> unionResult;

  // C++ 17+ required for destructuring
  for (const auto [value, numSetsIn] : flattened_value_count_map) {
    // Include value in the union if it is present in two or more sets
    if (numSetsIn >= 2) {
      unionResult.emplace(value);
    }
  }

  return unionResult;
}

int main() {
  std::set<int> set1, set2, set3, set4;

  set1.emplace(1);
  set1.emplace(2);

  set2.emplace(2);
  set2.emplace(3);

  set3.emplace(1);
  set3.emplace(4);

  set4.emplace(4);
  set4.emplace(5);

  for (const int value : unionOfIntersections({&set1, &set2, &set3, &set4})) {
    std::cout << value << '\n';
  }

  return EXIT_SUCCESS;
}