STL中集合的并、交、差 运算

声明

  • 今天一直在学习STL, 学习目录参考的是C语言编程网, 内容主要参考的是这个网站。 我学习的流程是按照C语言编程网的目录结构, 学到哪一个知识点就去www.cplusplus.com这个网站搜, 他网站自带的搜索不太好用, 我有时候会搜不到内容, 可以在必应搜索中指定网站搜索, 比如搜索set就按照set site:www.cplusplus.com这种关键词来搜索。
  • 主要是记录下来供自己日后参考, 因为一段时间不用就忘了, 所以是按照自己容易理解的方式写的, 不过任然希望各位可以指出错误和欠缺的地方, 共同进步。

集合的介绍

模板定义

  • 模板(文档连接)
    template < class T,                    // set::key_type/value_type
           class Compare = less<T>,        // set::key_compare/value_compare
           class Alloc = allocator<T>      // set::allocator_type
           > class set;
    
  • 介绍
    集合作为一种容器, 它的特殊性在于它的值是独一无二的(仅考虑set, 不考虑multiset), 联想高中学习的集合的3个性质, 无序性、确定性和互异性。在c++的集合中, 可以保证确定性和互异性, 但是没有无序性, 在set中, 元素的存储是有序的, 使用的比较方法就是上面模板中的less<T>。
    集合的其他使用方法不做介绍了, 这里仅介绍集合的3个运算方法, 并、交、差。在C++中分别是set_union(), set_intersection(), set_difference().下面重点介绍并集, 其它两个基本一样, 就换了个名字。

并集运算

模板定义

// 1
template <class InputIterator1, class InputIterator2, class OutputIterator>
OutputIterator set_union (InputIterator1 first1, InputIterator1 last1,
                         InputIterator2 first2, InputIterator2 last2,
                         OutputIterator result);
// 2
template <class InputIterator1, class InputIterator2, class OutputIterator, class Compare>
OutputIterator set_union (InputIterator1 first1, InputIterator1 last1,
                         InputIterator2 first2, InputIterator2 last2,
                         OutputIterator result, Compare comp);
  • 比较函数 comp 可以不指定, 一般情况下使用第一种即可。但是当使用自定义类型是就需要进行制定了,这个下面再说。

使用举例

int类型set使用举例

  • 由上面的模板定义可以看出, set_union()接受5个或6个参数, 前两个参数指出一个容器的开始和结束的位置, 接下来的两个参数指出另一容器的开始和结束的位置, 第五个参数指出需要插入容器的迭代器, 第六个参数是一个比较函数, 在使用已经有比较函数的类型的时候, 可以没有。
  • 第五个参数可以通过insert_iterator获取, 参考它的文档,观察其构造函数:
explicit insert_iterator (Container& x, typename Container::iterator i) : container(&x), iter(i) {}

知道该函数接受两个参数, 第一个参数是一个容器, 第二个参数是一个迭代器。当然也可以使用下面这种方式获取迭代器:

auto iter = std::insert(result, std::begin(result));

这个也是参考网站上示例的方式。

  • 根据上面的分析, 可以写出下面的代码
#include <iostream>
#include <string>
#include <utility>    // for pair<> & make_pair<>()
#include <set>	
#include <algorithm>
#include <iterator>

using std::cout;
using std::endl;
using std::string;
using intSet = std::set<int>;

void setUnion()
{
	intSet first = { 5, 10, 15, 20, 25 };
	intSet second = { 6 ,11, 16, 21, 26, 5, 15 ,20 };
	cout << "第一个集合中的元素时:\n";
	for (auto it : first) { cout << it << " "; }cout << endl;
	cout << "第二个集合中的元素时:\n";
	for (auto it : second) { cout << it << " "; }cout << endl;

	intSet result;

	std::insert_iterator<intSet> it(result, result.begin());
	std::set_union(first.begin(), first.end(), second.begin(), second.end(), it);
	cout << "集合的并集是:" << endl;
	for (auto it : result) { cout << it << " "; }cout << endl;
}

自定义类型set使用举例

  • 我们先自定义一个简单的类型
	class People
	{
	public:
		People(const string& fname, const string& sname):m_firstname(fname), m_secondname(sname) {}
		People() = default;
		friend std::ostream& operator<<(std::ostream& out, const People& people);
		friend std::istream& operator>>(std::istream& in, People& people);    // 方便输出
		
		// 将名字打包返回, 方便下一个进行名字的比较函数, 那个函数没有声明为友元函数, 所以无法直接访问该类的私有变量
		// 此处切不可返回引用, 只能使用值返回的方式, 否则会报错
		std::pair<string, string> getName() const
		{
			pair<string, string> ret;
			ret = std::make_pair(m_firstname, m_secondname);
			return ret;
		}
		
	private:
		string m_firstname;
		string m_secondname;
	};

	std::ostream& operator<<(std::ostream& out, const People& people)
	{
		out << people.m_firstname << " " << people.m_secondname;
		return out;
	}

	std::istream& operator>>(std::istream& in, People& people)
	{
		in >> people.m_firstname >> people.m_secondname;
		return in;
	}
  • 这个类有两个私有变量, m_firstname, 和 m_secondname。可以在类中直接重载<运算符作为比较函数, 像下面的代码所示, 如果在类内重载<运算符的话, 就不需要另外指定比较函数了。
	bool operator<(const People& otherPeople) const 
	{
		return m_secondname < otherPeople.m_secondname || m_secondname == otherPeople.m_secondname && m_firstname < otherPeople.m_firstname;
	}
  • 但是为了理解set_union()第六个参数的意义, 我采用在外部自定义一个比较函数的方式。如下所示:
	struct peopleComp
	{
		bool operator()(const People& people1, const People& people2)
		{
			std::pair<string, string> lname;
			std::pair<string, string> rname;
			lname = people1.getName();
			rname = people2.getName();

			return lname.second < rname.second || lname.second == rname.second && lname.first < rname.first;
		}
	}pComp;
  • 然后就可以使用下面的函数来进行集合的并集运算了
	void setTest()
	{
		using peopleSet = std::set<People, peopleComp>;

		peopleSet first = { {"liu", "bei"}, {"guan", "yu"}, {"zhang", "fei"} };
		peopleSet second = { {"liu", "bei"}, {"cao", "cao"}, {"sun", "quan"} };

		peopleSet result;

		cout << "第一个集合中的元素是:\n";
		for (auto it : first) { cout << it << " "; }cout << endl;
		cout << "第二个集合中的元素是:\n";
		for (auto it : second) { cout << it << " "; }cout << endl;
		
		std::insert_iterator<peopleSet> it(result, result.begin());
		set_union(first.begin(), first.end(), second.begin(), second.end(), it, pComp);
		cout << "二者的并集是:\n";
		for (auto it : result) { cout << it << " "; }cout << endl;
	}
  • 结果大概如下图所示
    运行结果

总结

  • 交集和差集的使用类似, 只是换了个名字。上面就是我对如何使用并、交、差运算方法的总结。当然于我而言最重要的并不是会使用这三种运算的基本语法, 而是找到了一种学习STL基础知识的方式。 于我而言, 最重要的两个资源就是C语言中文网和www.cplusplus.com这两个网站。 对于没有太长时间嚼书, 想要在短时间内掌握STL基础知识来说还是不错的, C语言中文网提供学习框架,www.cplusplus.com提供学习内容和示例。当然当有了时间之后还是希望自己可以比较系统完全的学习一下STL的,不过更多的还是要在实践中学习。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值