C++STL set/multiset容器的区别、pair对组创建、set容器排序、set排序 内置数据类型和自定义数据类型高级排序

1 set和multiset区别

区别:

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

set.insert() set不能有重复值插入

上一篇学习笔记知道set容器是不允许有重复值插入的,那么具体看看其中的原因。

首先,创建set容器,插入数据,选中insert→右键→转到定义,查看insert的定义
在这里插入图片描述
解释:
可以看到insert的返回值是pair类型,即返回值是对组类型,相当于返回值有两个数据,一个是迭代器iterator,表示插入值的位置,另一个是bool类型,表示这个值是否插入成功。对于set的insert而言,返回结果就是这个值是否插入成功,插入成功的话,也会有插入位置。其中,pair就是对组,是一组成对出现的数据。

multiset.insert() 允许有重复值插入
同样地,看看multiset容器中insert()函数是怎么定义的。
首先,创建set容器,插入数据,选中insert→右键→转到定义,查看insert的定义
在这里插入图片描述

解释:
在multiset容器中insert的返回值是一个迭代器,没有bool类型的返回值来判断是否重复插入,不像set容器中insert的返回值是pair对组类型。

接下来看看set容器和multiset容器重复插入一个值,insert的返回结果会有什么不一样。
测试代码:

void test1()
{
	int n = 30;

	cout << "set.insert() " << endl;
	set<int> s1;
	//insert的返回值类型是pair对组类型(成对出现的数据,数据1是迭代器,数据2是bool类型)
	pair<set<int>::iterator, bool> result1 = s1.insert(21);
	if (result1.second)//第二个数据是bool类型
	{
		cout << "第一次插入成功" << endl;//返回真 插入成功
	}
	else
	{
		cout << "第一次插入失败" << endl;
	}
	pair<set<int>::iterator, bool> result2 = s1.insert(21);
	if (result2.second)//第二个数据是bool类型
	{
		cout << "第一次插入成功" << endl;//返回真 插入成功

	}
	else
	{
		cout << "第一次插入失败" << endl;
	}
	cout << string(n, '-') << endl;
	
	cout << "multiset.insert() " << endl;
	multiset<int> s2;
	s2.insert(23);
	s2.insert(23);
	//insert的返回值类型是iterator类型 没有bool类型的返回值判断是否重复插入
	for (multiset<int>::iterator it = s2.begin(); it != s2.end(); it++)
	{
		cout << *it << "  ";
	}
	cout << endl;
	cout << string(n, '-') << endl;
}

在这里插入图片描述
解释:
可以看到在第二次插入值21时,insert第二个返回值是false,插入失败,无法插入重复值。也就是说insert第二个bool类型的返回值是用来检测重复值的,如果插入的是重复值,直接返回false;如果不是重复值,返回true。这很好地体现了set容器中为什么不能插入重复值。在set容器的定义中,如果有重复值插入,会直接返回一个插入失败结果

总结:

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

2 pair对组创建

功能描述: 成对出现的数据,利用对组可以返回两个数据

两种创建方式:

  • pair<type, type> p ( value1, value2 );
  • pair<type, type> p = make_pair( value1, value2 );
    type是指数据类型

示例:

void test1()
{
	int n = 20;

	cout << "第一种方式" << endl;
	pair<string, int> p1("Bella", 56);//类似默认构造 本质是类模板
	cout << "姓名:" << p1.first << "体重:" << p1.second << endl;//通过 . 访问第一个和第二个数据

	cout << string(n, '-') << endl;
	cout << "第二种方式" << endl;
	pair<string, int> p2 = make_pair("Bella", 54);
	cout << "姓名:" << p2.first << "体重:" << p2.second << endl;
}

在这里插入图片描述

总结: 两种方式都可以创建对组,记住一种即可

3 set容器排序

学习目标: set容器默认排序规则为从小到大,掌握如何改变排序规则

主要技术点: 利用仿函数,可以改变排序规则

3.1 set存放内置数据类型

在之前的学习中,set插入数据时就会对数据进行一个排序,并且默认的排序规则是从小到大。那么如何改变这个排序规则呢?

class myCompare
{
public:
	bool operator()(int value1, int value2) const
	{
		return value1 > value2;
	}
};

void test1()
{
	set<int> s1;
	s1.insert(21);
	s1.insert(22);
	s1.insert(23);
	s1.insert(24);
	s1.insert(25);
	cout << "默认排序规则为从小到大  s1:";
	for (set<int>::iterator it = s1.begin(); it != s1.end(); it++)
	{
		cout << *it << "  ";
	}
	cout << endl;

	set<int, myCompare> s2;
	s2.insert(21);
	s2.insert(22);
	s2.insert(23);
	s2.insert(24);
	s2.insert(25);
	cout << "指定排序规则为从大到小  s2:";
	for (set<int, myCompare>::iterator it2 = s2.begin(); it2 != s2.end(); it2++)
	{
		cout << *it2 << "  ";
	}
	cout << endl;

在这里插入图片描述

3.2 set存放自定义数据类型

class Person
{
public:
	Person(string name, int age, int height, int weight)
	{
		this->m_name = name;
		this->m_age = age;
		this->m_height = height;
		this->m_weight = weight;
	}
	string m_name;
	int m_age;
	int m_height;
	int m_weight;
};

class myCompare
{
public:
	bool operator()(const Person&p1, const Person&p2) const
	{
		if (p1.m_age == p2.m_age)
		{
			return p1.m_height > p2.m_height;
		}
		else if (p1.m_height == p2.m_height)
		{
			return p1.m_weight < p2.m_weight;
		}
		else
		{
			return p1.m_age > p2.m_age;
		}
	}
};

void test1()
{
	//创建人物
	set<Person, myCompare> s;
	string nameseed[] = { "张飞", "孙权", "西施", "貂蝉", "王昭君", "关羽" };
	int ageseed[] = { 28, 28, 25, 24, 26, 28 };
	int heightseed[] = { 178, 170, 153, 153, 153, 200 };
	int weightseed[] = { 140, 135, 108, 95, 100, 165 };
	for (int i = 0; i < 6; i++)
	{
		Person p(nameseed[i], ageseed[i], heightseed[i], weightseed[i]);
		s.insert(p);
	}
	cout << "自定义数据类型 set" << endl;
	for (set<Person, myCompare>::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << "姓名:" << it->m_name << "\t年龄:" << it->m_age
			<< "\t身高:" << it->m_height << "\t体重:" << it->m_weight << endl;
	}
	cout << endl;
}

在这里插入图片描述
注意点

  1. 在set还没有插入数据之前,就要指定set的排序规则,才会按照制定的排序规则插入数据;
  2. set的默认构造set<T> st; ,参数类型是类模板,因此这个仿函数也封装在类中;
  3. 仿函数,即重载小括号,operator();
  4. 仿函数的返回值是bool类型;
  5. 仿函数的形参取决于容器插入的数据类型。如果set插入的数据是int, 那么仿函数的形参也应该是int类型,即bool operator()(int v1, int v2) { }。如果set插入的数据是自定义数据类型Person, 那么仿函数的形参也应该是Person类型,即bool operator()(const Person& v1, const Person& v2) { },这里加入const修饰,防止数据类修改;使用引用防止浅拷贝。
  6. 如果要访问这个容器的数据,迭代器的作用域也要相应地变化,set<int, myCompare>::iteratorset<Person, myCompare>::iterator
  7. 在仿函数最后还要加上const修饰,否则会提示如下错误
    在这里插入图片描述

总结:

对于内置数据类型,利用仿函数可以指定set容器的排序规则即可;
对于自定义数据类型,set必须指定排序规则才可以插入数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值