【C++】--- STL之 set 和 map

在这里插入图片描述

一、关联式容器和键值对

在这里插入图片描述

1.关联式容器

(1)序列式容器:因为底层的数据结构是线性的,所以称它为序列式容器,比如说vector list deque 等等…

(2)关联式容器:也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。

2.键值对

什么叫做键值对???

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息。

比如:现在要建立一个英汉互译的字典,那该字典中必然有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应该单词,在词典中就可以找到与其对应的中文含义。

库中对 键值对的定义·:pair< first , second > (first = key second = value)

template <class T1, class T2>
struct pair 
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair(): first(T1()), second(T2())
{}
 
pair(const T1& a, const T2& b): first(a), second(b)
{}
};

二、set

1.set特点

  1. set是按照一定次序存储元素的容器
  2. 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。
  3. 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。
  4. set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代。
  5. set在底层是用二叉搜索树(红黑树)实现的。

2.set类

(1) set类对象构造

template < class T,                       
 			// set::key_type/value_type  元素的类型
           class Compare = less<T>,       
            // set::key_compare/value_compare 比较方式,默认小于
           class Alloc = allocator<T>      
           // set::allocator_type  使用STL提供的空间配置器管理方式
           > class set;
 
//构造set
explicit set (const key_compare& comp = key_compare(),
              const allocator_type& alloc = allocator_type());
template <class InputIterator>
 
//使用迭代器区间构造set
set (InputIterator first, InputIterator last,
       const key_compare& comp = key_compare(),
       const allocator_type& alloc = allocator_type());
 
//拷贝构造set
set (const set& x); 

(2)insert插入

(1)创建set对象:

#include<iostream>
#include<set>

using namespace std;

void test_set1()
{
	set<int> s;// 构造一个set对象

	set<int> s1(s.begin(), s.end());// 迭代器区间构造
	set<int> s2(s1);// 拷贝构造

}

(2)插入insert:

	s.insert(1);
	s.insert(1);
	s.insert(9);
	s.insert(3);
	s.insert(7);
	s.insert(5);

set的作用:排序+去重

(3)set遍历

(1)迭代器区间遍历:

	// 遍历
	set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		it++;
	}

(2)范围for:

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

在这里插入图片描述

(4)find查找

// 查找

	set<int>::iterator it1 = s.find(9);

	
		if (it1 != s.end())
		{
			cout << *it1 << endl;
		}
		else
		{
			cout << "找不到" << endl;
		}

在这里插入图片描述
在这里插入图片描述

(5)erase删除

void erase (iterator position);//删除指定位置元素
size_type erase (const value_type& val);//从set中删除指定的值
void erase (iterator first, iterator last);//删除指定区间

(1)删除指定位置元素:

删除元素5:

	set<int> s;
	s.insert(6);
	s.insert(2);
	s.insert(5);
	s.insert(8);
	s.insert(5);
 
	set<int>::iterator ret = s.find(5);
	if (ret != s.end())
	{
		s.erase(ret);
	}
 
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

(2)删除指定值元素

删除值为8的元素:

	set<int> s;
	s.insert(6);
	s.insert(2);
	s.insert(5);
	s.insert(8);
	s.insert(5);
 
	//删除值为8的元素
	s.erase(8);
 
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

(3)删除指定区间

删除5之前的元素:

	set<int> s;
	s.insert(6);
	s.insert(2);
	s.insert(5);
	s.insert(8);
	s.insert(5);
 
	//删除5之前的元素
	set<int>::iterator ret = s.find(5);
	s.erase(s.begin(), ret);
 
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

(6)计数count( )

set<int> s;// 构造一个set对象

	set<int> s1(s.begin(), s.end());// 迭代器区间构造
	set<int> s2(s1);// 拷贝构造

	s.insert(1);
	s.insert(1);
	s.insert(9);
	s.insert(3);
	s.insert(7);
	s.insert(5);
cout << s.count(1) << endl;

cout << s.count(1) << endl;
计算set里面传入参数元素的个数,因为他不允许重复出现,所以说只有一个。
在这里插入图片描述

(7)交换swap( )

set<int> s;// 构造一个set对象

	s.insert(1);
	s.insert(1);
	s.insert(9);
	s.insert(3);
	s.insert(7);
	s.insert(5);

	set<int> s1;
	s1.insert(2);
	s1.insert(4);
	s1.insert(6);
	s1.insert(8);
	s1.insert(10);


	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	swap(s, s1);

	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

在这里插入图片描述

(8)清空所有元素clear( )

s.clear();
	cout << "clear后的s" << endl;
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

在这里插入图片描述

(9)求set的元素个数size( )

cout << s1.size() << endl;

在这里插入图片描述

三、map

1.map特点

  1. map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素。
  2. 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,为其取别名称为pair:
typedef pair<const key, T> value_type;
  1. 在内部,map中的元素总是按照键值key进行比较排序的。
  2. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
  3. map支持下标访问符,即在[ ]中放入key,就可以找到与key对应的value。
  4. map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。

2.map类

(1)map类的构造

template < class Key,                                     // map::key_type,Key的类型
           class T,                                       // map::mapped_type,value的类型
           class Compare = less<Key>,                     // map::key_compare,比较器类型,默认小于,自定义类型需写函数指针或仿函数
           class Alloc = allocator<pair<const Key,T> >    // map::allocator_type 空间配置器
           > class map;
 
//构造map
explicit map (const key_compare& comp = key_compare(),
              const allocator_type& alloc = allocator_type());
 
使用迭代器区间构造map
template <class InputIterator>
  map (InputIterator first, InputIterator last,
       const key_compare& comp = key_compare(),
       const allocator_type& alloc = allocator_type());
 
//拷贝构造map
map (const map& x);

(2)插入insert( )

map的插入函数的函数原型如下:

pair<iterator,bool> insert (const value_type& val);

insert函数的参数显示是value_type类型的,实际上value_type就是pair类型的别名

typedef pair<const Key, T> value_type;

下面介绍了4种插入方法,其中第4种就是多参数的构造函数支持隐式类型转换!是最常用的,也是最简洁的!!!

void test_map()
{
	map<string,string> dict;

	pair<string, string> kv1("string","字符串");
	
	dict.insert(kv1);// 1、插入有名对象

	dict.insert(pair<string, string>("right", "右边"));// 2、插入匿名对象

	dict.insert(make_pair("test", "测试"));// 3、调用函数模版

	dict.insert({ "left","左边" });// 4、多参数的构造函数,支持隐式类型转换(C++11 常用!!!)

	//
}

int main()
{
	//test_set1();

	test_map();
	return 0;
}

(3)map遍历

(1)迭代器遍历:
在这里插入图片描述

// 遍历:
	map<string, string>::iterator it = dict.begin();

	while (it != dict.end())
	{
		cout << it->first << ":" << it->second << endl;
		it++;
	}
	cout << endl;

在这里插入图片描述
这里遍历的顺序是按照key的字典序来进行遍历的!

(2)范围for遍历:

for (auto e : dict)
	{
		cout << e.first << ":" << e.second << endl;
	}
	cout << endl;

在这里插入图片描述

(4)删除erase( )

在这里插入图片描述
也就是说,我们既可以根据key值删除指定元素,也可以根据迭代器删除指定元素,若是根据key值进行删除,则返回实际删除的元素个数。

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

int main()
{
	map<int, string> m;
	m.insert(make_pair(2, "two"));
	m.insert(make_pair(1, "one"));
	m.insert(make_pair(3, "three"));
	//方式一:根据key值进行删除
	m.erase(3);
	//方式二:根据迭代器进行删除
	map<int, string>::iterator pos = m.find(2);
	if (pos != m.end())
	{
		m.erase(pos);
	}
	return 0;
}

(5)查找find()

在这里插入图片描述

	auto it = dict.find("string");
	
	if (it != dict.end())
	// 如果找到了就会返回他的迭代器,如果没找到就会返回这个map对象的end。
	{
		cout << it->second << endl;
	}
	else
	{
		cout << "找不到" << endl;
	}

	auto it1 = dict.find("str");
	if (it1 != dict.end())
	// 如果找到了就会返回他的迭代器,如果没找到就会返回这个map对象的end。
	{
		cout << it1->second << endl;
	}
	else
	{
		cout << "找不到" << endl;
	}

在这里插入图片描述

(6)operator[ ](重要)

在这里插入图片描述
map的[ ]运算符重载函数的函数原型如下:

mapped_type& operator[] (const key_type& k);

[ ]运算符重载函数的参数就是一个key值,而这个函数的返回值如下:

(*((this->insert(make_pair(k, mapped_type()))).first)).second

就这样看着不太好理解,我们整理一下,实际上[ ]运算符重载实现的逻辑实际上就是以下三个步骤:

  1. 调用insert函数插入键值对。
  2. 拿出从insert函数获取到的迭代器。
  3. 返回该迭代器位置元素的值value。

总之一句话总结:传参传的是k(调用insert函数把参数key插入),然后返回的是:value&

在这里插入图片描述

传参传的是:key
返回的是:value&
不管插入成功还是失败,pair中的iterator始终指向key所在节点的iterator。
如果插入失败,那么插入(insert)就相当于查找(find)

在这里插入图片描述
这个函数操作应用在: 计数 上极大缩短了代码量:

// 统计次数
void test_map2()
{
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
"苹果", "香蕉", "苹果", "香蕉","苹果","草莓", "苹果","草莓" };

	map<string, int> countMap;

	 法1:

	//for (auto& e : arr)
	//{
	//	// 这里的map对象:countMap是 一边遍历,一边插入形成二叉搜索树!
	//	auto it = countMap.find(e);
	//	if (it != countMap.end())
	// 如果在二叉搜索树里面没有找到 就会返回countMap的end()
	//	{
	//		it->second++; // 找到了,second++
	//	}
	//	else
	//	{
	//		countMap.insert({ e,1 }); // 没有找到就初始化 1
	//	}
	//}

	// 法2:operator[]的运用!(传参传的是key,返回的是val&)
	for (auto& e : arr)
	{
		countMap[e]++;
	}

四、multiset 和 multimap

multimap容器与map容器的底层实现一样,也都是平衡搜索树(红黑树),其次,multimap容器和map容器所提供的成员函数的接口都是基本一致的,这里也就不再列举了,multimap容器和map容器的区别与multiset容器和set容器的区别一样,multimap允许键值冗余,即multimap、multiset 容器当中存储的元素是可以重复的

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

int main()
{
	multimap<int, string> mm;
	//插入元素(允许重复)
	mm.insert(make_pair(2, "two"));
	mm.insert(make_pair(2, "double"));
	mm.insert(make_pair(1, "one"));
	mm.insert(make_pair(3, "three"));
	for (auto e : mm)
	{
		cout << "<" << e.first << "," << e.second << ">" << " ";
	}
	cout << endl; //<1,one> <2,two> <2,double> <3,three>
	return 0;
}

在这里插入图片描述

其次,由于multimap容器允许键值冗余,调用[ ]运算符重载函数时,应该返回键值为key的哪一个元素的value的引用存在歧义,因此在multimap容器当中没有实现[ ]运算符重载函数。


好了,今天的分享就到这里了
如果对你有帮助,记得点赞👍+关注哦!
我的主页还有其他文章,欢迎学习指点。关注我,让我们一起学习,一起成长吧!

在这里插入图片描述

  • 48
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论
STL是指标准模板库(Standard Template Library),它是C++语言的一部分,提供了一系列的模板类和函数,用于支持通用的数据结构和算法。STL的目标是提供高效、可重用和可扩展的组件,以便开发人员能够更轻松地编写高质量的代码。STL包含了许多常见的数据结构,如vector、list、setmap等,以及各种算法,比如排序、查找、遍历等。通过使用STL,开发人员可以更加高效地处理各种数据结构和算法的问题,提高代码的开发效率和质量。 在STL中,我们可以使用各种容器来存储和管理数据。例如,我们可以使用std::map来创建一个键值对的映射,其中每个键都有一个与之相关联的值。下面是一个示例代码,展示了如何创建和使用一个std::map对象: std::map<std::string, int> disMap() { std::map<std::string, int> tempMap{ {"C语言教程",10},{"STL教程",20} }; return tempMap; } std::map<std::string, int> newMap(disMap()); 在这个示例中,disMap()函数创建了一个临时的std::map对象,并初始化了其中的一些键值对。然后,使用移动构造函数将这个临时对象移动到了一个新的std::map对象newMap中。最终,我们可以通过newMap对象来访问和操作这些键值对。 综上所述,STL是C++中的标准模板库,提供了一系列的模板类和函数,用于支持通用的数据结构和算法。STL的使用可以提高代码的开发效率和质量,并且通过各种容器和算法,可以方便地处理各种数据结构和算法的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [C++ STL详解超全总结(快速入门STL)](https://blog.csdn.net/qq_50285142/article/details/114026148)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【C++实验】阅读STL源码并分析](https://blog.csdn.net/qq_35760825/article/details/125311509)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小能软糖_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值