C++STL之map详解

跳转STL主目录

6. map

6.1 介绍

映射类似于函数的对应关系,每个x对应一个y,而map是每个键对应一个值。会python的朋友学习后就会知道这和python的字典非常类似。

比如说:学习 对应 看书,学习 是键,看书 是值。
学习->看书
玩耍 对应 打游戏,玩耍 是键,打游戏 是值。
玩耍->打游戏

//头文件
#include<map>
//初始化定义
map<string, string> mp;
map<string, int> mp;
map<int, node> mp;//node是结构体类型

map特性:map会按照键的顺序从小到大自动排序,键的类型必须可以比较大小

6.2 函数方法

6.2.1 函数方法

代码含义
mp.find(key)返回键为key的映射的迭代器 $O(logN) $ 注意:用find函数来定位数据出现位置,它返回一个迭代器。当数据存在时,返回数据所在位置的迭代器,数据不存在时,返回 m p . e n d ( ) mp.end() mp.end()
mp.erase(it)删除迭代器对应的键和值 O ( l o g N ) O(logN) O(logN)
mp.erase(key)根据映射的键删除键和值 O ( l o g N ) O(logN) O(logN)
mp.erase(first,last)删除左闭右开区间迭代器对应的键和值 O ( l a s t − f i r s t ) O(last-first) O(lastfirst)
mp.size()返回映射的对数$ O(1)$
mp.clear()清空map中的所有元素 O ( N ) O(N) O(N)
mp.insert()插入元素,插入时要构造键值对
mp.empty()如果map为空,返回true,否则返回false
mp.begin()返回指向map第一个元素的迭代器(地址)
mp.end()返回指向map尾部的迭代器(最后一个元素的下一个地址)
mp.rbegin()返回指向map最后一个元素的迭代器(地址)
mp.rend()返回指向map第一个元素前面(上一个)的逆向迭代器(地址)
mp.count(key)查看元素是否存在,因为map中键是唯一的,所以存在返回1,不存在返回0
mp.lower_bound()返回一个迭代器,指向键值>= key的第一个元素
mp.upper_bound()返回一个迭代器,指向键值> key的第一个元素

6.2.2 注意点

下面说明部分函数方法的注意点

注意:
查找元素是否存在时,可以使用
mp.find()mp.count()mp[key]
但是第三种情况,如果不存在对应的key时,会自动创建一个键值对(产生一个额外的键值对空间)
所以为了不增加额外的空间负担,最好使用前两种方法

6.2.3 迭代器进行正反向遍历

  • mp.begin()mp.end()用法:

用于正向遍历map

map<int,int> mp;
mp[1] = 2;
mp[2] = 3;
mp[3] = 4;
auto it = mp.begin();
while(it != mp.end()) {
	cout << it->first << " " << it->second << "\n";
	it ++;
}

结果:

1 2
2 3
3 4
  • mp.rbegin()mp.rend()

用于逆向遍历map

map<int,int> mp;
mp[1] = 2;
mp[2] = 3;
mp[3] = 4;
auto it = mp.rbegin();
while(it != mp.rend()) {
	cout << it->first << " " << it->second << "\n";
	it ++;
}

结果:

3 4
2 3
1 2

6.2.4 二分查找

二分查找lower_bound() upper_bound()

map的二分查找以第一个元素(即键为准),对进行二分查找
返回值为map迭代器类型

#include<bits/stdc++.h>
using namespace std;

int main() {
	map<int, int> m{{1, 2}, {2, 2}, {1, 2}, {8, 2}, {6, 2}};//有序
	map<int, int>::iterator it1 = m.lower_bound(2);
	cout << it1->first << "\n";//it1->first=2
	map<int, int>::iterator it2 = m.upper_bound(2);
	cout << it2->first << "\n";//it2->first=6
	return 0;
}

6.3 添加元素

//先声明
map<string, string> mp;
  • 方式一:
mp["学习"] = "看书";
mp["玩耍"] = "打游戏";
  • 方式二:插入元素构造键值对
mp.insert(make_pair("vegetable","蔬菜"));
  • 方式三:
mp.insert(pair<string,string>("fruit","水果"));
  • 方式四:
mp.insert({"hahaha","wawawa"});

6.4 访问元素

6.4.1 下标访问

(大部分情况用于访问单个元素)

mp["菜哇菜"] = "强哇强";
cout << mp["菜哇菜"] << "\n";//只是简写的一个例子,程序并不完整

6.4.2 遍历访问

  • 方式一:迭代器访问
map<string,string>::iterator it;
for(it = mp.begin(); it != mp.end(); it++) {
	//      键                 值 
	// it是结构体指针访问所以要用 -> 访问
	cout << it->first << " " << it->second << "\n";
	//*it是结构体变量 访问要用 . 访问
	//cout<<(*it).first<<" "<<(*it).second;
}
  • 方式二:智能指针访问
for(auto i : mp)
cout << i.first << " " << i.second << endl;//键,值
  • 方式三:对指定单个元素访问
map<char,int>::iterator it = mp.find('a');
cout << it -> first << " " <<  it->second << "\n";
  • 方式四:c++17特性才具有
for(auto [x, y] : mp)
	cout << x << " " << y << "\n";
//x,y对应键和值

6.5 与unordered_map的比较

这里就不单开一个大目录讲unordered_map了,直接在map里面讲了。

6.5.1 内部实现原理

map:内部用红黑树实现,具有自动排序(按键从小到大)功能。

unordered_map:内部用哈希表实现,内部元素无序杂乱。

6.5.2 效率比较

map

  • 优点:内部用红黑树实现,内部元素具有有序性,查询删除等操作复杂度为 O ( l o g N ) O(logN) O(logN)

  • 缺点:占用空间,红黑树里每个节点需要保存父子节点和红黑性质等信息,空间占用较大。

unordered_map

  • 优点:内部用哈希表实现,查找速度非常快(适用于大量的查询操作)。
  • 缺点:建立哈希表比较耗时。

两者方法函数基本一样,差别不大。

注意:

  • 随着内部元素越来越多,两种容器的插入删除查询操作的时间都会逐渐变大,效率逐渐变低。

  • 使用[]查找元素时,如果元素不存在,两种容器都是创建一个空的元素;如果存在,会正常索引对应的值。所以如果查询过多的不存在的元素值,容器内部会创建大量的空的键值对,后续查询创建删除效率会大大降低

  • 查询容器内部元素的最优方法是:先判断存在与否,再索引对应值(适用于这两种容器)

    // 以 map 为例
    map<int, int> mp;
    int x = 999999999;
    if(mp.count(x)) // 此处判断是否存在x这个键
        cout << mp[x] << "\n";   // 只有存在才会索引对应的值,避免不存在x时多余空元素的创建
    

另外:

还有一种映射:multimap

键可以重复,即一个键对应多个值,如要了解,可以自行搜索。

如要获取所有内容的PDF文件,请在公众号【行码棋】回复【STL】获取,非常抱歉了。
Update:2023-12-11更新PDF文件

C++ STL(Standard Template Library)是C++标准库中的一个重要组成部分,提供了一组数据结构和算法的模板类,可以大大简化C++程序的开发过程。STL包含了多个容器类,每个容器类都有其特定的特性和用途。 STL中的容器类主要分为序列容器和关联容器两大类。序列容器包括vector、list、deque和array,它们按照元素在容器中的位置进行存储和访问。关联容器包括set、multiset、map、multimap和unordered系列容器,它们按照键值进行存储和访问。 序列容器具有以下特性: 1. 动态大小:序列容器可以根据需要动态调整大小,可以在任意位置插入和删除元素。 2. 快速随机访问:序列容器中的元素可以通过索引快速访问,时间复杂度为O(1)。 3. 按顺序存储:序列容器中的元素按照插入的顺序存储,并保持元素的相对位置不变。 4. 支持迭代器:序列容器提供了迭代器,可以通过迭代器遍历容器中的元素。 关联容器具有以下特性: 1. 自动排序:关联容器中的元素按照键值自动排序,并且可以根据自定义的比较函数进行排序。 2. 快速查找:关联容器支持快速的查找操作,时间复杂度为O(log n)。 3. 不允许重复键值:set和map容器中的键值是唯一的,而multiset和multimap容器允许重复的键值。 4. 无序容器:unordered系列容器是C++11引入的,它们使用哈希函数来存储和访问元素,查找操作的平均时间复杂度为O(1)。 总而言之,C++ STL提供了丰富的容器类,每个容器类都有其独特的特性和适用场景,可以根据具体需求选择合适的容器来存储和操作数据。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [C++——STL容器](https://blog.csdn.net/JAN6055/article/details/122758690)[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/Jinyizhi2233/article/details/131640448)[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 ]
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

行码棋

码字好辛苦,总结好吃力

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

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

打赏作者

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

抵扣说明:

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

余额充值