C++之STL的algorithm(7)之集合运算相关算法(交集、并集、差集、inserter适配器)整理

C++之STL的algorithm(7)之集合运算相关算法(交集、并集、差集)整理

注:整理一些突然学到的C++知识,随时mark一下
例如:忘记的关键字用法,新关键字,新数据结构



提示:本文为 C++ 中set_intersection、set_union和set_difference的写法和举例


一、 集合相关操作算法

  集合算法即对两个容器求交、并、补的数学运算。set_intersection、set_union和set_difference算法被定义在<algorithm>头文件中,它们用于计算两个有序序列之间的交集、并集和差集。这些算法通常与std::vector、std::list、std::set、std::multiset等容器配合使用,但也可以用于其他有序序列。请注意,对于std::map和std::multimap这类键值对容器,这些算法也是适用的,因为它们内部是有序的。

1、set_intersection算法求交集

将两个容器(有序,set自动排序)的交集赋给第三个容器。
语法:

template< class InputIt1, class InputIt2, class OutputIt >  
OutputIt set_intersection( InputIt1 first1, InputIt1 last1,  
                           InputIt2 first2, InputIt2 last2,  
                           OutputIt d_first );

参数:

first1, last1: 指向第一个输入序列的起始和结束迭代器。
first2, last2: 指向第二个输入序列的起始和结束迭代器。
d_first: 指向输出序列的起始迭代器。

返回:

指向输出序列中最后一个元素的下一个位置的迭代器。

举例:

#include <iostream>  
#include <vector>  
#include <set>  
#include <algorithm>  
  
int main() {  
    std::vector<int> v1 = {1, 2, 3, 4, 5};  
    std::vector<int> v2 = {4, 5, 6, 7, 8};  
    std::vector<int> v_intersection;  
      
    std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(v_intersection));  
      
    for (int num : v_intersection) {  
        std::cout << num << ' ';  
    }  
    // 输出: 4 5  
  
    // 对于set  
    std::set<int> s1 = {1, 2, 3, 4, 5};  
    std::set<int> s2 = {4, 5, 6, 7, 8};  
    std::set<int> s_intersection;  
      
    std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), std::inserter(s_intersection, s_intersection.begin()));  
      
    for (int num : s_intersection) {  
        std::cout << num << ' ';  
    }  
    // 输出: 4 5  
}

2、set_union算法求并集

将两个容器(有序,set自动排序)的并集赋给第三个容器。
语法:

template< class InputIt1, class InputIt2, class OutputIt >  
OutputIt set_union( InputIt1 first1, InputIt1 last1,  
                    InputIt2 first2, InputIt2 last2,  
                    OutputIt d_first );

参数:
与set_intersection相同。

返回:
与set_intersection相同。

举例:

#include <iostream>  
#include <vector>  
#include <set>  
#include <algorithm>  
  
int main() {  
    std::vector<int> v1 = {1, 2, 3, 4, 5};  
    std::vector<int> v2 = {4, 5, 6, 7, 8};  
    std::vector<int> v_union;  
      
    std::set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(v_union));  
      
    for (int num : v_union) {  
        std::cout << num << ' ';  
    }  
    // 输出: 1 2 3 4 5 6 7 8  
  
    // 对于set  
    std::set<int> s1 = {1, 2, 3, 4, 5};  
    std::set<int> s2 = {4, 5, 6, 7, 8};  
    std::set<int> s_union;  
      
    std::set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), std::inserter(s_union,
    s_union.begin()));

	for (int num : s_union) {  
   	 	std::cout << num << ' ';  
	}  
// 输出: 1 2 3 4 5 6 7 8
}

3、set_difference算法求差集

将两个容器(有序,set自动排序)的差集赋给第三个容器。差集A-B即集合A减去AB的交集。

语法:

template< class InputIt1, class InputIt2, class OutputIt >  
OutputIt set_difference( InputIt1 first1, InputIt1 last1,  
                          InputIt2 first2, InputIt2 last2,  
                          OutputIt d_first );

参数:
与set_intersection相同。

返回:
与set_intersection相同。

举例:

#include <iostream>  
#include <vector>  
#include <set>  
#include <algorithm>  
  
int main() {  
    std::vector<int> v1 = {1, 2, 3, 4, 5};  
    std::vector<int> v2 = {4, 5, 6, 7, 8};  
    std::vector<int> v_difference;  
      
    std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(v_difference));  
      
    for (int num : v_difference) {  
        std::cout << num << ' ';  
    }  
    // 输出: 1 2 3  
  
    // 对于set  
    std::set<int> s1 = {1, 2, 3, 4, 5};  
    std::set<int> s2 = {4, 5, 6, 7, 8};  
    std::set<int> s_difference;  
      
    std::set_difference(s1.begin(), s1.end(), s2.begin(), s2.end(), std::inserter(s_difference, s_difference.begin()));  
      
    for (int num : s_difference) {  
        std::cout << num << ' ';  
    }  
    // 输出: 1 2 3  
}

二、关于参数中的 back_inserter 和 inserter

在上面的例子中,std::back_inserter 是一个迭代器适配器,它用于在容器的尾部插入元素。当你调用 set_intersection、set_union 或 set_difference 等算法时,这些算法需要一个输出迭代器,用于指向你想要插入结果的容器的位置

对于 std::vector,使用 std::back_inserter 是非常合适的,因为 std::vector 是一个动态数组,它允许在尾部高效地添加元素。std::back_inserter 内部持有一个指向 vector 的引用,并使用 push_back 成员函数来添加新元素。因此,当你通过 std::back_inserter 插入元素时,vector 会自动调整其大小以容纳新元素

这是使用 std::back_inserter 的一个例子:

std::vector<int> result;  
std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(result));

在这个例子中,set_intersection 算法会将交集的结果插入到 result 向量的尾部。每次算法找到一个交集元素时,它就会调用 std::back_inserter 的 operator=,这实际上会调用 result.push_back() 来添加新元素。

相比之下,如果你直接传递 result.begin() 作为输出迭代器,那么算法会尝试直接在 result 的开始位置写入元素,这通常会导致未定义行为,因为 result 可能没有足够的空间来容纳所有结果,或者算法可能会覆盖掉 result 中已有的元素。

对于 std::set 和 std::multiset,情况稍有不同。这些容器不允许在任意位置插入元素,而只允许在特定的位置(根据元素的排序顺序)插入元素。因此,对于 set 和 multiset,通常使用 std::inserter 而不是 std::back_inserter,并将迭代器指向容器的 begin(),因为 std::inserter 使用 insert 成员函数来添加元素,这允许在正确的位置插入元素而保持容器的排序状态。

例如:

std::set<int> result;  
std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), std::inserter(result, result.begin()));

在这个例子中,std::inserter 使用 result.insert() 来在正确的位置插入交集元素,从而保持 result 的排序状态。

总之,选择使用 std::back_inserter 还是 std::inserter 取决于你正在使用的容器类型以及你希望如何插入元素。对于 std::vector,通常使用 std::back_inserter;对于 std::set 和 std::multiset,则使用 std::inserter。

总结

对于std::vector,上述算法均假设vector已经排序。如果vector未排序,需要先对其进行排序,否则结果将是不正确的。
对于std::setstd::multiset,由于它们内部自动维护排序,因此可以直接使用这些算法。
对于std::mapstd::multimap,这些算法同样适用,因为它们也是有序的。

  • 17
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值