C++中如何优雅实现三集合(A∩B)∪(B∩C)∪(A∩C)及单行求交集
Great questions! Let's break down solutions for both of your requests:
1. Implementing (A ∩ B) ∪ (B ∩ C) ∪ (A ∩ C) without 4 extra sets
Your original approach uses 4 intermediate sets, but we can cut that down to just one result set by leveraging the fact that std::set automatically handles duplicate elements. Instead of storing each intersection in a separate set, we can directly insert the results of each intersection into the final result set—since duplicates will be ignored automatically.
Here's the optimized code:
#include <set> #include <algorithm> using namespace std; int main() { set<int> set1 = {1, 2}; set<int> set2 = {2, 3}; set<int> set3 = {1, 4}; set<int> result; // Insert elements from A∩B directly into result set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), inserter(result, result.begin())); // Insert elements from B∩C (set auto-deduplicates duplicates) set_intersection(set2.begin(), set2.end(), set3.begin(), set3.end(), inserter(result, result.begin())); // Insert elements from A∩C set_intersection(set1.begin(), set1.end(), set3.begin(), set3.end(), inserter(result, result.begin())); // Result is {1, 2} which matches the expected union of intersections return 0; }
This eliminates the need for res1, res2, and res3 entirely—only one extra set (result) is required, which is way better than the original 4.
2. Single-line (or clean) implementation for three-set intersection
For the intersection of three sets (A ∩ B ∩ C), we can write concise code either by nesting set_intersection calls or using modern C++ features. Here are a few options:
Option 1: Nested set_intersection (C++11+)
You can chain the intersection operations using a temporary set for the first intermediate result. To make it "single-line" in practice, wrap it in a template function for reusability:
template <typename T> set<T> three_set_intersection(const set<T>& a, const set<T>& b, const set<T>& c) { set<T> ab_intersect; set_intersection(a.begin(), a.end(), b.begin(), b.end(), inserter(ab_intersect, ab_intersect.begin())); set<T> abc_intersect; set_intersection(ab_intersect.begin(), ab_intersect.end(), c.begin(), c.end(), inserter(abc_intersect, abc_intersect.begin())); return abc_intersect; } // Call it in one line: set<int> three_intersect = three_set_intersection(set1, set2, set3);
Option 2: C++20 Ranges & contains (cleaner, more efficient)
If you're using C++20 or later, you can use ranges and std::set::contains (a faster alternative to count()) to filter elements that exist in all three sets:
#include <ranges> #include <set> // One-line conversion to set: set<int> three_intersect(set1 | std::views::filter([&](int x) { return set2.contains(x) && set3.contains(x); }));
This is more readable than nested algorithm calls and avoids intermediate sets entirely (the range view is evaluated lazily).
Bonus: Even more elegant approach for your original union-of-intersections expression
For (A ∩ B) ∪ (B ∩ C) ∪ (A ∩ C), we can rephrase the logic: it's all elements that appear in at least two of the three sets. Using C++20 ranges, this becomes extremely clean:
set<int> result( std::views::concat(set1, set2, set3) | std::views::filter([&](int x) { int count = 0; count += set1.contains(x); count += set2.contains(x); count += set3.contains(x); return count >= 2; }) | std::views::unique );
This avoids all set_intersection and set_union calls entirely, replacing them with a straightforward filter based on element presence.
内容的提问来源于stack exchange,提问作者James

