C++中set/multiset容器(黑马程序员)

目录


set/multiset 容器


视频与文档链接



注意:set和multiset容器包含的头文件都是:#include



1 set基本概念

简介:

  • 所有元素都会在插入时自动被排序(从小到大)

set容器的迭代器也不支持随机访问


本质:

  • set/multiset属于关联式容器(特点是插入时自动被排序),底层结构是用二叉树实现。

set和multiset区别

  • set不允许容器中有重复的元素
  • multiset允许容器中有重复的元素





2 set构造和赋值

功能描述:创建set容器以及赋值

构造:

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

赋值:

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

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


void test01() {
	// 默认构造
	set<int> s1;

	// set容器插入数据只有insert这一种方式
	s1.insert(11);
	s1.insert(5); 
	s1.insert(0);
	s1.insert(100);
	s1.insert(100);
	cout << "容器s1的内容如下:" << endl;
	// 遍历容器
	for (set<int>::iterator it=s1.begin();it!=s1.end();it++) {
		cout << *it << "   ";


	}
	cout << endl;
	cout << "容器s1大小为:" << s1.size() << endl;
	cout << "可以看到,我们像set容器里插入了5个数,其中有2个数相同,都为100" << endl;
	cout << "但是最后只打印出了4个数据,且容器大小为4,不是5。" << endl<<endl<<endl;

	// 拷贝构造
	set<int> s2=s1;
	cout << "s2拷贝自s1,s2的内容如下:" << endl;
	for (set<int>::iterator it = s2.begin(); it != s2.end(); it++) {
		cout << *it << "   ";


	}

	cout << endl << endl;

	set<int>s3 = s2;
	cout << "s3=s2,s3里的内容如下:" << endl;
	for (set<int>::iterator it = s3.begin(); it != s3.end(); it++) {
		cout << *it << "   ";


	}
	cout << endl << endl;


}


int main() {
	test01();
	cin.get();
	return 0;



}

在这里插入图片描述
总结:

  • set容器插入数据时只能用insert
  • set容器插入数据的数据会自动排序

set容器不允许插入重复的数据,编译器不会报错。但是打印不出来,而且访问不到,相当于没插,容器里根本没这个重复的数。







3 set大小和交换

功能描述:

  • 统计set容器大小以及交换set容器

set容器没有resize()调整大小函数


函数原型:

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

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

// 打印函数
void printSet(set<int> s) {
	for (set<int>::iterator it = s.begin(); it != s.end(); it++) {
		cout << *it << "   ";


	}
	cout << endl;
}

void test01() {
	set<int> s1;
	 
	s1.insert(10);
	s1.insert(20);
	s1.insert(5);
	s1.insert(26);
	s1.insert(3);
	cout << "s1交换前:" << endl;
	printSet(s1);
	if (s1.empty() == 1) {
		cout << "set容器为空!" << endl;

	}

	else
	{
		cout << "set容器非空!!" << endl;
		cout << "大小为:" << s1.size() << endl << endl;
	}

	set<int> s2;
	cout << "s2容器交换前:" << endl;
	s2.insert(0); s2.insert(0); s2.insert(1); s2.insert(4);
	printSet(s2); cout << "s2的大小为:" << s2.size() << endl<<endl;
	
	s1.swap(s2);
	cout << "s1与s2交换后,s1变为:" << endl;
	printSet(s1);
	cout << "s1的大小:" << s1.size() << endl<<endl;

	cout << "s2变为:" << endl;
	printSet(s2);
	cout << "s2的大小=" << s2.size() << endl;


}

int main() {
	test01();
	cin.get();
	return 0;


}

在这里插入图片描述
总结:

  • 统计大小 — size
  • 判断是否为空 — empty
  • 交换容器 — swap






4 set插入和删除

功能描述:

  • set容器进行插入数据和删除数据

set容器只有insert一种插入数据方式,而且不能指定位置。只能一个个地插,插入时数据自动被排序。不过set容器删除数据时可以指定位置


set容器的迭代器不支持随机访问


函数原型:

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

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

// 打印函数
void printSet(set<int> s) {
	for (set<int>::iterator it = s.begin(); it != s.end(); it++) {
		cout << *it << "   ";


	}
	cout << endl;
}

void test01() {
	set<int> s1;

	s1.insert(10);
	s1.insert(20);
	s1.insert(5);
	s1.insert(26);
	s1.insert(3);
	cout << "容器s1里的内容如下:" << endl;
	printSet(s1);
	cout << endl;
	
	// 删除
	// 注意set容器的迭代器不支持随机访问
	s1.erase(s1.begin(), ++s1.begin());
	cout << "删除s1容器里[s1.begin(),++s1.begint())这个区间的数据" << endl;
	printSet(s1); cout << endl;
	
	// 清空
	s1.clear();
	cout << "清空s1里的数据" << endl;
	cout << "s1的大小为:"<<s1.size();


}

int main() {
	test01();
	cin.get();
	return 0;


}

在这里插入图片描述







5 set查找和统计

功能描述:

  • 对set容器进行查找数据以及统计数据

函数原型:

  • find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();set.end()不能解引用
  • count(key); //统计key的元素个数,这个元素个数要么为0,要么为1

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


void test01() {
	set<int> s1;
	s1.insert(11);
	s1.insert(5);
	s1.insert(0);
	s1.insert(100);
	s1.insert(100);
	cout << "s1里的内容如下:" << endl;
	// 遍历容器
	for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {
		cout << *it << "    ";


	}
	cout << endl;
	cout <<"s1的大小为:"<<s1.size() << endl;
	cout << endl;
	// 查找
	cout << endl;
	set<int>::iterator it1;
	set<int>::iterator it2;
	it1 = s1.find(100);
	it2 = s1.find(500);
	if (it1 == s1.end()) {
		cout << "元素100未找到!!" << endl;
	}
	else {
		cout << "元素100已找到!!" << endl;
		
	}
	if (it2 == s1.end()) {
		cout << "元素500未找到!!" << endl;
	}
	else {
		cout << "元素500已找到!!" << endl;
	}
    	

	// 统计
	cout<<endl<<endl<<"s1里等于100的数据有"<<s1.count(100)<<"个"<<endl;
}


int main() {
	test01();
	cin.get();
	return 0;



}

在这里插入图片描述

总结:

  • 查找 — find (返回的是迭代器)
  • 统计 — count (对于set,结果为0或者1)






6 set和multiset的区别

区别:

  • set不可以插入重复数据,而multiset可以
  • set插入数据的同时会返回插入结果,表示插入是否成功
  • multiset不会检测数据,因此可以插入重复数据

分析一下set容器的insert函数,从而验证set插入数据的同时会返回插入结果,表示插入是否成功。

在这里插入图片描述



在这里插入图片描述



通过查看insert函数的定义发现,他会返回一个pair类型。pair类型又是个结构体,里面有两个数。

解析:

  1. pair代表对组类型。
    对组:成对出现的一组数据

  2. insert返回pair<iterator,bool>。
    其中iterator(迭代器):代表插入的位置
    bool(布尔变量):代表插入是否成功。true代表成功,false代表失败




这是multiset容器的insert函数,他只返回一个迭代器,并不检测数据。
在这里插入图片描述




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


void test01() {
	set<int> s1;
	pair<set<int>::iterator, bool> ret1 = s1.insert(100);
	// 注意使用对组里数据的方法
	if (ret1.second) {
		cout << "向set容器里第一次插入100成功!" << endl;

	}
	else {
		cout << "向set容器里第一次插入100失败!" << endl;
	}
	pair<set<int>::iterator, bool> ret2 = s1.insert(100);
	if (ret2.second) {
		cout << "向set容器里第二次插入100成功!" << endl;

	}
	else {
		cout << "向set容器里第二次插入100失败!" << endl;
	}
	cout << endl << endl;

	// multiset
	multiset<int> m1;
	m1.insert(99);
	m1.insert(100);
	m1.insert(88);
	m1.insert(66);
	cout << "multiset容器里的数据如下:" << endl;
	for (multiset<int>::iterator it = m1.begin(); it != m1.end(); it++) {
		cout << *it << "   ";
	}cout << endl << endl;;
	cout << "再向multiset容器里插入两个100后,容器里的数据为:" << endl;
	m1.insert(100);
	m1.insert(100);
	for (multiset<int>::iterator it = m1.begin(); it != m1.end(); it++) {
		cout << *it << "   ";
	}cout << endl;
	cout << endl;
	
}


int main() {
	test01();
	cin.get();
	return 0;



}

在这里插入图片描述

总结:

  • 如果不允许插入重复数据可以利用set
  • 如果需要插入重复数据利用multiset

multiset容器使用方法与set容器基本一致,但multiset没有插入数据检测,因此可以重复插入数据。它的insert函数只返回一个迭代器,表示插入数据的位置。







7 pair对组创建

功能描述:

  • 成对出现的数据,利用对组可以返回两个数据
使用对组时不需要包含头文件

两种创建方式:

  • pair<type, type> p ( value1, value2 );
  • pair<type, type> p = make_pair( value1, value2 );


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



void test01() {
	pair<string, int> ret1("asdasd",25);
	cout << "第一种方式创建对组" << endl;
	cout << "姓名:" << ret1.first << "    " << "年龄:" << ret1.second << endl<<endl;

	cout << "第二种方式创建对组" << endl;
	pair<string, int> ret2=make_pair("ll;l,l,;", 35);
	cout << "姓名:" << ret2.first << "    " << "年龄:" << ret2.second << endl;


}

int main() {
	test01();
	cin.get();
	return 0;


}

在这里插入图片描述







8 set容器排序

学习目标:

  • set容器默认排序规则为从小到大,掌握如何改变排序规则

主要技术点:

  • 利用仿函数,可以改变排序规则


8.1 内置类型指定排序规则

注意:set容器在插入数据时就会自动排序,所以我们要在插入数据前就得修改排序规则

利用仿函数(它包含在一个类里,类中有各个数据类型的仿函数)来指定排序规则,在set模板参数列表中再加一个参数

在这里插入图片描述
第二个参数有默认值,现在我们要给他赋值。


// 排序规则,利用仿函数,仿函数就是重载()
// 之不过仿函数要封装在类里
class Mycompare {
public:
	// 第一个()是重载的意思,第二个()里放参数
	// 注意最后要加一个const,这是C++最新规则规定的
	
	bool operator()(int num1, int num2) const{
		return num1 > num2;
	}


};
 // 然后把类名加到set参数列表里面去
set<int,Mycompare>s2;



	s2.insert(10);
	s2.insert(20);
	s2.insert(40);
	s2.insert(30);
	s2.insert(5);
	for (set<int>::iterator it = s2.begin(); it != s2.end(); it++) {
		cout << *it << "   ";

	}
	cout << endl;





综合:

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

// 打印函数
void printSet(set<int> s) {
	for (set<int>::iterator it = s.begin(); it != s.end(); it++) {
		cout << *it << "    ";


	}
	cout << endl;
}

// 排序规则,利用仿函数,他是个类
class Mycompare {
public:
	// 第一个()是重载的意思
	bool operator()(int num1, int num2) const{
		return num1 > num2;
	}



};
// 针对内置的数据类型



void test01() {
	set<int>s1;
	s1.insert(10);
	s1.insert(20);
	s1.insert(40);
	s1.insert(30);
	s1.insert(5);
	cout << "没有修改排序规则的set容器s1:" << endl;
	printSet(s1); cout << endl;

	// 指定排序规则为从大到小
	// 第二个参数直接输入类名
	set<int,Mycompare>s2;



	s2.insert(10);
	s2.insert(20);
	s2.insert(40);
	s2.insert(30);
	s2.insert(5);
	cout << "将s2的排序规则修改为降序:" << endl;
	for (set<int>::iterator it = s2.begin(); it != s2.end(); it++) {
		cout << *it << "   ";

	}
	cout << endl;
}

int main() {
	test01();
	cin.get();
	return 0;



}

在这里插入图片描述

总结:利用仿函数可以指定set容器的排序规则





8.2 自定义数据类型指定排序规则

#include<iostream>
using namespace std;
#include<set>
#include<string>
// 打印函数


// 针对自定义的数据类型
class Person {
public:
	string m_Name;
	int m_Age;
	Person(string name,int age):m_Name(name),m_Age(age){}

};
// 排序规则,利用仿函数,他是个类
class Mycompare {
public:
	// 第一个()是重载的意思
	// 按照年龄进行降序
	bool operator()(Person p1, Person p2) const{
		return p1.m_Age > p2.m_Age;
	}



};

void test01() {
	Person p1("asddsa", 25);
	Person p2("waeeee", 36);
	Person p3("男枪", 46);
	Person p4("NAVI", 76);
	set<Person,Mycompare> s1;
	s1.insert(p1);
	s1.insert(p2);
	s1.insert(p3);
	s1.insert(p4);

	// 看看他默认是如何排序的
	// 这样子肯定不能输出,他怎么知道按照哪个规则排序呢???
	// 所以自定义类型必须指定排序规则
	for (set<Person>::iterator it = s1.begin(); it != s1.end(); it++) {
		cout << "姓名:" << it->m_Name << "   " << "年龄:" << it->m_Age << endl;



	}
	cout << endl;




}

int main() {
	test01();
	cin.get();
	return 0;



}

在这里插入图片描述

总结:对于自定义数据类型,set必须指定排序规则才可以插入数据

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
multisetC++标准库的一个容器,它是一个有序的集合,允许重复的元素存在。它在头文件<set>定义。 multiset容器的用法如下: 1. 创建multiset对象: ```cpp std::multiset<int> mySet; ``` 2. 插入元素: 使用insert()函数向multiset插入元素。由于multiset允许重复的元素存在,因此可以插入相同的元素。 ```cpp mySet.insert(10); mySet.insert(20); mySet.insert(10); ``` 3. 遍历multiset: 可以使用迭代器来遍历multiset的元素。 ```cpp for(auto it = mySet.begin(); it != mySet.end(); ++it) { std::cout << *it << " "; } ``` 4. 查找元素: 使用find()函数可以查找multiset的元素。如果找到了指定的元素,则返回指向该元素的迭代器;如果没找到,则返回end()迭代器。 ```cpp auto it = mySet.find(20); if(it != mySet.end()) { std::cout << "Found: " << *it << std::endl; } else { std::cout << "Not found" << std::endl; } ``` 5. 删除元素: 使用erase()函数可以删除multiset的元素。可以删除指定值的元素,也可以删除指定位置的元素。 ```cpp mySet.erase(10); // 删除所有值为10的元素 auto it = mySet.find(20); if(it != mySet.end()) { mySet.erase(it); // 删除指定位置的元素 } ``` multiset容器的特点是它的元素会根据特定的排序规则进行自动排序,因此在插入和删除元素时会有一定的性能开销。但是它提供了高效的查找操作,适用于需要有序且允许重复元素的场景。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值