[学习C++]STL 算法vector/set集合-交集,并集,差集,对称差

版权声明:本文为博主原创文章,https://blog.csdn.net/kalilili/article/details/42177279

针对这里提及的四个集合运算必须特别注意: 
1、第一个算法需保证第一集合和第二集合有序,并从小到大排序,内部使用默认“<”操作符比较元素大小; 

2、第二个算法需保证第一集合和第二集合有序,排序方式参照Compare确定,内部使用Compare比较元素大小。

1 -- set_intersection(交集)


 
 
  1. template < class InputIterator1, class InputIterator2, class OutputIterator>
  2. OutputIterator set_intersection( InputIterator1 first1, InputIterator1 last1,
  3. InputIterator2 first2, InputIterator2 last2,
  4. OutputIterator result);
  5. template < class InputIterator1, class InputIterator2, class OutputIterator, class Compare>
  6. OutputIterator set_intersection( InputIterator1 first1, InputIterator1 last1,
  7. InputIterator2 first2, InputIterator2 last2,
  8. OutputIterator result, Compare comp);

该函数用于求两个集合的交集,结果集合中包含所有同时属于第一个集合和第二个集合的元素。例如:集合{1,2,3,7,9}和{3,4,5,7}的交集为{3,7}。 
函数返回值:结果集合的结束位置的back_insert_iterator(和普通的迭代器不样)。
参数:

(第一个集合的开始位置,第一个集合的结束位置,第二个参数的开始位置,第二个参数的结束位置,结果集合的插入迭代器(inserter(result, result.begin()))

对于第二个算法,Compare指定用于比较元素大小的仿函数。 

2 -- set_union(并集)


 
 
  1. template < class InputIterator1, class InputIterator2, class OutputIterator>
  2. OutputIterator set_union( InputIterator1 first1, InputIterator1 last1,
  3. InputIterator2 first2, InputIterator2 last2,
  4. OutputIterator result);
  5. template < class InputIterator1, class InputIterator2, class OutputIterator, class Compare>
  6. OutputIterator set_union( InputIterator1 first1, InputIterator1 last1,
  7. InputIterator2 first2, InputIterator2 last2,
  8. OutputIterator result, Compare comp);


 
该函数用于求两个集合的交集,结果集合中包含所有同时属于第一个集合和第二个集合的元素。例如:集合{1,2,3,7,9}和{3,4,5,7}的并集为{1,2,3,4,5,7}。  

3 -- set_difference(差集)


 
 
  1. template < class InputIterator1, class InputIterator2, class OutputIterator>
  2. OutputIterator set_difference( InputIterator1 first1, InputIterator1 last1,
  3. InputIterator2 first2, InputIterator2 last2,
  4. OutputIterator result);
  5. template < class InputIterator1, class InputIterator2, class OutputIterator, class Compare>
  6. OutputIterator set_difference( InputIterator1 first1, InputIterator1 last1,
  7. InputIterator2 first2, InputIterator2 last2,
  8. OutputIterator result, Compare comp);
  9. 该函数用于求两个集合的差集,结果集合中包含所有属于第一个集合但不属于第二个集合的元素。例如:集合{ 1, 2, 3, 7, 9}和{ 3, 4, 5, 7}的差集为{ 1, 2, 9}。
该函数用于求两个集合的差集,结果集合中包含所有属于第一个集合但不属于第二个集合的元素。例如:集合{1,2,3,7,9}和{3,4,5,7}的差集为{1,2,9}。 

4 -- set_symeetric_difference(对称差集)


 
 
  1. template< class InputIterator1, class InputIterator2, class OutputIterator>
  2. OutputIterator set_symmetric_difference( InputIterator1 first1, InputIterator1 last1,
  3. InputIterator2 first2, InputIterator2 last2,
  4. OutputIterator result);
  5. template< class InputIterator1, class InputIterator2, class OutputIterator, class Compare>
  6. OutputIterator set_symmetric_difference( InputIterator1 first1, InputIterator1 last1,
  7. InputIterator2 first2,
  8. InputIterator2 last2,
  9. OutputIterator result, Compare comp);
数学上,两个集合的对称差集是只属于其中一个集合,而不属于另一个集合的元素组成的集合。也就是说对称差集是去除同时出现在两个集合中的元素后,两集合其他元素组成的集合。例如:集合{1,2,3,7,9}和{3,4,5,7}的对称差为{1,2,4,5,9}。集合论中的这个运算相当于布尔逻辑中的异或运算。集合A和B的对称差通常表示为AΔB。 


应用举例(以并集为例):

第一类--两个数组求并:


 
 
  1. // set_union example
  2. #include <iostream>
  3. #include <algorithm>
  4. #include <vector>
  5. using namespace std;
  6. int main () {
  7. int first[] = { 5, 10, 15, 20, 25};
  8. int second[] = { 50, 40, 30, 20, 10};
  9. vector< int> v; // 也可以用set<int> // 0 0 0 0 0 0 0 0 0 0
  10. vector< int>::iterator it;
  11. sort (first,first+ 5); // 5 10 15 20 25
  12. sort (second,second+ 5); // 10 20 30 40 50
  13. set_union (first, first+ 5, second, second+ 5, inserter(v, v.begin()));
  14. // 5 10 15 20 25 30 40 50 0 0
  15. for( vector< int>::iterator it=v.begin();it!=v.end();it++)
  16.         cout<<*it<< " ";
  17. return 0;
  18. }

 第二类两个set求并:


 
 
  1. #include <set>
  2. #include <iterator>
  3. #include <iostream>
  4. #include <algorithm>
  5. using namespace std;
  6. int main(void)
  7. {
  8.     set< int> a,b,c; //c也可以定义成vector
  9.     a.insert( 1);
  10.     a.insert( 6);
  11.     a.insert( 6);
  12.     b.insert( 2);
  13.     b.insert( 6);
  14.     b.insert( 9);
  15.     //最后一个参数若使用c.begin()会产生编译错误assignment of read-only localtion.
  16.     set_union(a.begin(), a.end(), b.begin(), b.end(), inserter(c, c.begin()));
  17.     for( set< int>::iterator it=c.begin();it!=c.end();it++)
  18.         cout<<*it<< " ";
  19.     return 0;
  20. }

第三类--两个vector之间求并:


 
 
  1. #include <vector>
  2. #include <iterator>
  3. #include <iostream>
  4. #include <algorithm>
  5. using namespace std;
  6. int main()
  7. {
  8. vector< int> a,b,c;
  9. for( int e= 0;e< 10;e++)
  10. {
  11. a.push_back(e);
  12. b.push_back(e+ 5);
  13. }
  14. //最后一个参数若使用c.begin(),运行时会出错“Segmentation fault (core dumped)”.
  15. set_union(a.begin(),a.end(),b.begin(),b.end(),inserter(c, c.begin()));
  16. for( vector< int>::iterator it=c.begin();it!=c.end();it++)
  17. cout<<*it<< " ";
  18. return 0;
  19. }

注意事项: 函数参数的最后一个参数是插入迭代器,是因为这个函数内部有对结果集合的插入过程,必须用到插入函数,若不需要插入就用普通迭代器即可,就提前就把结果集合的内存空间扩大。

比如:


 
 
  1. #include <vector>
  2. #include <iterator>
  3. #include <iostream>
  4. #include <algorithm>
  5. using namespace std;
  6. int main()
  7. {
  8. vector< int> a,b,c( 20); //初始化c中有20个0
  9. for( int e= 0;e< 10;e++)
  10. {
  11. a.push_back(e);
  12. b.push_back(e+ 5);
  13. }
  14. //最后一个参数若使用c.begin(),运行时会出错“Segmentation fault (core dumped)”.
  15. set_union(a.begin(),a.end(),b.begin(),b.end(),c.begin());
  16. for( vector< int>::iterator it=c.begin();it!=c.end();it++)
  17. cout<<*it<< " ";
  18. return 0;
  19. }


若改为c(3)会出现3个元素,最后RE。


此时函数的最后一个参数是普通迭代器,函数的返回值也不再是插入迭代器,也变成了普通迭代器(指向结果集合的最后一个插入元素(非0的))

比如:


 
 
  1. #include <iostream>
  2. #include <algorithm>
  3. #include <vector>
  4. using namespace std;
  5. int main () {
  6. int first[] = { 5, 10, 15, 20, 25};
  7. int second[] = { 50, 40, 30, 20, 10};
  8. vector< int> v( 10); // 0 0 0 0 0 0 0 0 0 0
  9. vector< int>::iterator it;
  10. sort (first,first+ 5); // 5 10 15 20 25
  11. sort (second,second+ 5); // 10 20 30 40 50
  12. it=set_union (first, first+ 5, second, second+ 5,v.begin()); // 5 10 15 20 25 30 40 50 0 0
  13. //如果v.begin()改成inserter(v, v.begin()),函数返回值是插入迭代器,就会出现编译错误,错误信息:
  14. /*E:\Users\amdi\Desktop\zuoye.cpp|165|error: no match for 'operator=' (operand types are 'std::vector<int>::iterator { aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >}' and 'std::insert_iterator<std::vector<int> >')| */
  15. cout << "union has " << int(it - v.begin()) << " elements.\n";
  16. return 0;
  17. }

所以求结果集合的元素个数除了用result.size()以外,也可以用以上程序的方法,不过建议还是用插入迭代器,用result.size()毕竟用普通迭代器的问题范围小,而且不方便(我们可能不想去预知结果集合的大小)。

C++中,我们可以使用STL(Standard Template Library)提供的容器如set或unordered_set来操作集合交集并集、补差集对称差集。这里简述一下基本的概念: 1. **交集(Intersection)**:两个集合的元素都存在的部分,可以使用`std::set_intersection`函数,或者直接用迭代器遍历两个集合,比较每个元素是否都在另一个集合中。 ```cpp std::set<int> A = {1, 2, 3, 4}; std::set<int> B = {3, 4, 5, 6}; std::set<int> intersection; std::set_intersection(A.begin(), A.end(), B.begin(), B.end(), inserter(intersection, intersection.begin())); ``` 2. **并集(Union)**:两个集合的所有元素合并在一起,可以用`std::merge`函数或直接将两个集合相加。 ```cpp union(A, B); // 直接赋值操作 intersection.clear(); // 清空交集后添加结果 ``` 3. **补(Complement)**:第一个集合中不包含在第二个集合中的元素,需要创建一个新的集合来存储,然后遍历第一个集合删除已存在元素。 ```cpp std::vector<int> complement(A.begin(), A.end()); std::set_difference(B.begin(), B.end(), complement.begin(), complement.end(), inserter(complement, complement.begin())); ``` 4. **差集(Difference)**:第一个集合中特有的元素,同样需要创建新集合并从第一个集合中移除出现在第二个集合中的元素。 ```cpp std::set_difference(A.begin(), A.end(), B.begin(), B.end(), inserter(diff, diff.begin())); ``` 5. **对称差集(Symmetric Difference)**:返回两个集合中独有的元素,既不在其中一个集合中而在另一个集合中的元素。 ```cpp std::set_symmetric_difference(A.begin(), A.end(), B.begin(), B.end(), inserter(symmetric_diff, symmetric_diff.begin())); ``` 6. **幂(Power Set)**:生成所有可能的子,包括空和原集合本身,这通常通过递归或回溯算法实现,C++标准库没有提供直接操作功能,需要自定义算法。 上述代码展示了基本的操作,实际使用时记得处理可能出现的异常,并确保数据类型匹配。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值