zl程序教程

您现在的位置是:首页 >  其他

当前栏目

11 STL-set/multiset

2023-04-18 15:26:12 时间

 重新系统学习c++语言,并将学习过程中的知识在这里抄录、总结、沉淀。同时希望对刷到的朋友有所帮助,一起加油哦!

 

每一次学习都是为了追求智慧!

写在前面,本篇章主要介绍STL中常用容器set/multiset。

1.1 set基本概念

本质:

        set和multiset,属于关联式容器,底层结构是用二叉树实现的。

特性:

        所有元素都会在插入时自动被排序。

set和multiset区别:

  • set 不允许容器内有重复元素,可重复插入元,但只保存一份。
  • multiset 允许容器内有重复元素。


1.2 set构造和赋值

构造函数:

  • set<T> st;                //默认构造函数:
  • set(const set &st);         //拷贝构造函数

赋值:

  • set& operator=(const set &st);         //重载等号操作符

示例:

#include <iostream>
#include <string>
#include<set>
using namespace std;
void printSet(const set<int>& s) {
	for (auto item : s) {
		cout << item << " ";
	}
	cout << endl;
}

void test() {
	set<int> s;
	// set插入数据只有insert方式
	s.insert(2);
	s.insert(4);
	s.insert(2);
	s.insert(3);
	s.insert(1);

	// 不能插入重复的值,就算重复插入,也只保留一份数据
	// 元素在插入时自动被排序,默认按照升序
	printSet(s);

	// 拷贝构造函数
	set<int> s2(s);
	printSet(s2);

	//赋值
	set<int> s3;
	s3 = s2;
	printSet(s3);
}

int main() {
	test();

	system("pause");
	return 0;
}


1.3 set大小和交互

函数原型:

  • size();   //返回容器中元素的数目
  • empty();         //判断容器是否为空
  • swap(st);         //交换两个集合容器

示例:

#include <iostream>
#include <string>
#include<set>
using namespace std;

//size(); //返回容器中元素的数目
//empty(); //判断容器是否为空
//swap(st); //交换两个集合容器
void printSet(const set<int>& s) {
	for (auto item : s) {
		cout << item << " ";
	}
	cout << endl;
}

void test() {
	set<int> s;
	s.insert(2);
	s.insert(1);
	s.insert(1);
	s.insert(3);
	printSet(s);

	if (s.empty()) {
		cout << "s is empty" << endl;
	}
	else {
		cout << "s is not empty" << endl;
		cout << "s size:" << s.size() << endl;
	}

	set<int> s2;
	s2.insert(10);
	s2.insert(30);
	s2.insert(20);
	printSet(s2);

	cout << "change s and s2:" << endl;
	s.swap(s2);
	printSet(s);
	printSet(s2);
}


int main() {
	test();

	system("pause");
	return 0;
}


1.4 set插入和删除

函数原型:

  • insert(elem);                 //在容器中插入元素。
  • clear();                         //清除所有元素
  • erase(pos);                 //删除pos迭代器所指的元素,返回下一个元素的迭代器。
  • erase(beg, end);         //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
  • erase(elem);                 //删除容器中值为elem的元素。

示例:

#include <iostream>
#include <string>
#include<set>

using namespace std;

void printSet(const set<int>& s) {
	for (set<int>::const_iterator it = s.begin(); it != s.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

void test() {
	set<int> s;

	s.insert(2);
	s.insert(1);
	s.insert(3);
	s.insert(4);
	s.insert(5);

	printSet(s);

	//erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。
	set<int>::const_iterator it = s.erase(s.begin());
	cout << *it << endl;// 返回下一个元素的迭代器  元素值2
	printSet(s);

	//erase(elem); //删除容器中值为elem的元素。
	s.erase(2);
	printSet(s);

	set<int> s2(s);

	//erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
	s.erase(s.begin(), s.end());
	printSet(s);

	cout << "s2:" << endl;
	printSet(s2);

	//clear(); //清除所有元素
	s2.clear();
	cout << "s2 after clear:" << endl;
	printSet(s2);
}

int main() {
	test();

	system("pause");
	return 0;
}


1.5 set查找和统计

函数原型:

  • find(key);     //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
  • count(key);  //统计key的元素个数。set 只会返回0和1,multiset是0和n。

示例:

#include <iostream>
#include <string>
#include<set>
using namespace std;

void test() {
	set<int> s;
	s.insert(2);
	s.insert(2);
	s.insert(1);
	s.insert(3);
	s.insert(4);
	s.insert(5);

	//find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
	set<int>::iterator pos = s.find(2);
	if (pos != s.end()) {
		cout << "finded:" << *pos << endl;
	}
	else {
		cout << "not find" << endl;
	}

	//count(key); //统计key的元素个数
	int n = s.count(2);
	cout << "s中2的个数:" << n << endl;
	n = s.count(9);
	cout << "s中9的个数:" << n << endl;
}

int main() {
	test();

	system("pause");
	return 0;
}


1.6 set和multiset区别

区别:

        (1) 能否插入重复数据:

                se不可以,multiset可以;

        (2) 插入数据后返回插入成功失败结果:

                set 返回;multiset不返回,所以可以插入重复数据。

示例:

#include <iostream>
#include <string>
#include<set>
using namespace std;

// set 和multiset区别
template<class T>
void myPrint(T& s) {
	for (auto item : s) {
		cout << item << " ";
	}
	cout << endl;
}

void test() {
	set<int> s;
	pair<set<int>::iterator, bool> ret=s.insert(1);
	if (ret.second) {
		cout << "第一次插入成功" << endl;
	}
	else {
		cout << "第一次插入失败" << endl;
	}

	ret = s.insert(1);
	if (ret.second) {
		cout << "第二次插入成功" << endl;
	}
	else {
		cout << "第二次插入失败" << endl;
	}

	myPrint(s);
}

// multiset 会插入重复数据,并且在插入时也会做好排序
void test2() {
	multiset<int> ms;
	ms.insert(4);
	ms.insert(2);
	ms.insert(1);
	ms.insert(1);
	ms.insert(3);
	ms.insert(1);
	ms.insert(1);

	myPrint(ms);
}

int main() {
	test();

	test2();

	system("pause");
	return 0;
}


1.7 pair对组创建

功能:

        成对出现的数据,可以用队组来承载。

函数原型:

  •         pair<type, type>  p (val1, val2);                               //创建队组
  •         pari<type, type> p = make_pair(val1, val2);            //创建队组
  •         p.first                                                                        // 获取第一个元素
  •         p.second                                                                 // 获取第二个元素

示例:

#include <iostream>
#include <string>

using namespace std;


void test() {
	pair<string, int> p1("tom", 19);
	pair<string, int> p2 = make_pair("echo", 18);

	cout << "name: " << p1.first << ",age: " << p1.second << endl;
	cout << "name: " << p2.first << ",age: " << p2.second << endl;
}

int main() {
	test();

	system("pause");
	return 0;
}


1.8 set容器排序

问题:

        set 容器在插入时会自动给数据排序,且默认是从小到大。那么如果改变排序规则?

方法:

        利用防函数,来改变排序规则。

特性:

        set存放自定义数据类型,必须指定排序规则;

        且指定规则为主键,重复数据只能存入一份。

 

示例: set存放内置数据类型排序规则从大到小

#include <iostream>
#include <string>
#include<set>
using namespace std;
// set存放内置数据类型排序规则从大到小
 class MyCompare { 
public: 
	bool operator()(int v1, int v2) const
	{ 
		return v1 > v2;
	} 
};

void test01()
{
	set<int> s1; 
	s1.insert(10);
	s1.insert(40);
	s1.insert(20); 
	s1.insert(30);
	s1.insert(50);
	//默认从小到大
	for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;

	//指定排序规则
	set<int,const MyCompare> s2;
	s2.insert(10);
	s2.insert(40);
	s2.insert(20);
	s2.insert(30);
	s2.insert(50);

	for (set<int, MyCompare>::iterator it = s2.begin(); it != s2.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

int main() {
	test01();

	system("pause");
	return 0;
}

示例: set存放自定义数据类型排序规则从大到小

#include <iostream>
#include <string>
#include<set>
using namespace std;
class Person {
public:
	Person(string name,int age) {
		this->m_name = name;
		this->m_age = age;
	}


	string m_name;
	int m_age;
};

class MyCompare {
public:
	bool operator()(const Person& p1, const Person& p2)const {
		// 按照年龄降序
		
		// 如果年龄相同,想再跟进姓名排序,这样写
		//if (p1.m_age == p2.m_age) {
		//	return p1.m_name > p2.m_name;
		//}

		return p1.m_age > p2.m_age;
	}
};

void test() {
	// 自定义的书记雷,都需要指定排序规则,不然无法插入set
	// 本案例按照年龄降序来排序
	// 则年龄是主键,会发现年龄18的数据只能插入一条
	set<Person,MyCompare> s;
	s.insert(Person("tom", 18));
	s.insert(Person("echo", 19));
	s.insert(Person("lucy", 18));
	s.insert(Person("lily", 20));

	for (auto item : s) {
		cout << "name: " << item.m_name
			<< " age: " << item.m_age
			<< " " << endl;
	}

}

int main() {
	test();

	system("pause");
	return 0;
}