当前位置: 首页 > news >正文

stl--std::map

 map

模板类

实现原理

红黑树存储键值对,红黑树的key就是传递的key,value是pair对象。

注意一些函数的参数,比如find函数:利用key寻找值,返回迭代器,而不是利用值寻找值。

find(key)在 map 容器中查找键为 key 的键值对,如果成功找到,则返回指向该键值对的双向迭代器;反之,则返回和 end() 方法一样的迭代器。另外,如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。

map容器的迭代器

一定要注意:map容器中存放的不是键值对,也不是值。而是pair模板结构体,pair中才是存储键值对。

对map容器的迭代器进行指向操作,指向的是pair结构体中的函数或者变量。

对于map的迭代器(iterator),对其解引用后,就是一个pair对象,所以iterator->first = 键、iterator->second = 值。

map容器和其他容器迭代器解引用的相同点和不同点

相同点:解引用的结果都是容器中存储的元素(对象)。

不同点:

其他容器解引用出来的元素就是存储的值;

map容器解引用出来的是也是其元素,但是这个元素是一个pair对象,而不直接就是存储的值。

总结一句话:

容器中存储的是什么,迭代器解引用就是的结果就是什么。

map容器建立和存储的过程

建立map容器

容器内建立pair对象存储键值对

容器内建立RB-tree对象存储pair。

map容器初始化和赋值方法

1,赋值:{{},{}}赋值法。

2,拷贝:利用赋值构造函数:map<int,string>ffmap(fmap);

3,截取:

map 类模板还支持取已建 map 容器中指定区域内的键值对,创建并初始化新的 map 容器。例如:

  1. std::map<std::string, int>myMap{ {"C语言教程",10},{"STL教程",20} };
  2. std::map<std::string, int>newMap(++myMap.begin(), myMap.end());

这种方法注意end()的选择,如果要选择到最后,不要--mymap.end();

4,下标赋值。

        map<int,string>mymap{{0,"fangfang"},{1,"xiaoli"}};auto ite=mymap.find(1);cout<<(*ite).second<<endl;cout<<ite->first<<" "<<ite->second<<endl;map<int,string> fmap;fmap[0]="aaaa";fmap[1]="bbbb";fmap[2]="cccc";int i=0;for(i;i<fmap.size();i++){cout<<fmap[i]<<" ";}cout<<endl;map<int,string>ffmap(fmap);for(i=0;i<ffmap.size();i++){cout<<ffmap[i]<<" ";}cout<<endl;

map容器不能像vector一样从数组中获取值。

5,insert插入法:

insert可以先建立pair键值对再插入,也可以插入临时值(右值引用插入):

int main()
{map<string,string>mymap;pair<map<string,string>::iterator,bool> ret=mymap.insert({"China","Beijing"});cout<<ret.first->first<<"---"<<ret.first->second<<endl;pair<string,string> add={"Americ","Niuyake"};ret=mymap.insert(add);cout<<ret.first->first<<"---"<<ret.first->second<<endl;return 0;
}
~                

注意:

(1,pair键值对的定义,

(2,insert返回类型以及如何定义返回类型变量。

(3,insert还可以同时插入多个键值对。

关于Insert更多看-------连接

6,两个效率更高的插入方法:

1》

template <class... Args>
  pair<iterator,bool> emplace (Args&&... args);

  • 当该方法将键值对成功插入到 map 容器中时,其返回的迭代器指向该新插入的键值对,同时 bool 变量的值为 true;
  • 当插入失败时,则表明 map 容器中存在具有相同键的键值对,此时返回的迭代器指向此具有相同键的键值对,同时 bool 变量的值为 false。
  • 返回类型同insert

2》

template <class... Args>
  iterator emplace_hint (const_iterator position, Args&&... args);

  1. 该方法不仅要传入创建键值对所需要的数据,还需要传入一个迭代器作为第一个参数,指明要插入的位置(新键值对键会插入到该迭代器指向的键值对的前面);
  2. 该方法的返回值是一个迭代器,而不再是 pair 对象。当成功插入新键值对时,返回的迭代器指向新插入的键值对;反之,如果插入失败,则表明 map 容器中存有相同键的键值对,返回的迭代器就指向这个键值对。

     3. 成功,返回一个指向键值对的迭代器。

int main()
{map<string,int>mymap;pair<map<string,int>::iterator,bool> ret=mymap.emplace("China",1);cout<<ret.first->first<<"  "<<ret.first->second<<endl;map<string,int>::iterator ite=mymap.emplace_hint(mymap.end(),"Americ",2);cout<<ite->first<<"  "<<ite->second<<endl;return 0;
}

map访问值的方法

1,迭代器指向second对象:ite-second;

2,迭代器解引用之后引用second:(*ite).second;

3,下标访问(键作为下标访问):

需要特别注意的是:这个下标是键值,而不一定是0,1,2这些数字,。

eg:

mymap["YunNan"]

因为map是可以修改值的值的,所以:

mymap["YunNan"]="sanqizhixiang"

注意,只有当 map 容器中确实存有包含该指定键的键值对,借助重载的 [ ] 运算符才能成功获取该键对应的值;反之,若当前 map 容器中没有包含该指定键的键值对,则此时使用 [ ] 运算符将不再是访问容器中的元素,而变成了向该 map 容器中增添一个键值对。其中,该键值对的键用 [ ] 运算符中指定的键,其对应的值取决于 map 容器规定键值对中值的数据类型,如果是基本数据类型,则值为 0;如果是 string 类型,其值为 "",即空字符串(即使用该类型的默认值作为键值对的值)。
 

4,除了借助 [ ] 运算符获取 map 容器中指定键对应的值,还可以使用 at() 成员方法。和前一种方法相比,at() 成员方法也需要根据指定的键,才能从容器中找到该键对应的值;不同之处在于,如果在当前容器中查找失败,该方法不会向容器中添加新的键值对,而是直接抛出 out_of_range 异常。

mymap.at("YunNan");

注意:键和值的类型任意,不是键只能为int。

[ ]和at()

[ ]:
 

#include <iostream>
#include <map>int main() {std::map<std::string, int> my_map;my_map["apple"] = 10;my_map.insert(std::pair<std::string, int>("banana", 20));my_map.insert(std::make_pair("orange", 30));my_map.insert({"grape", 40});// Accessing values using [] operatorstd::cout << my_map["apple"] << std::endl;// Accessing values using at() methodstd::cout << my_map.at("banana") << std::endl;// Accessing values using find() methodauto it = my_map.find("orange");if (it != my_map.end()) {std::cout << it->second << std::endl;}// Accessing values using iteratorfor (auto it = my_map.begin(); it != my_map.end(); ++it) {std::cout << it->first << " : " << it->second << std::endl;}// Accessing values not existing in the map// using [] operatorstd::cout << my_map["mango"] << std::endl; // This will throw an exceptionif (my_map.find("mango") != my_map.end()) {std::cout << "exist mango in map" << std::endl;}return 0;
}

at():

#include <iostream>
#include <map>int main() {std::map<std::string, int> my_map;my_map["apple"] = 10;my_map.insert(std::pair<std::string, int>("banana", 20));my_map.insert(std::make_pair("orange", 30));my_map.insert({"grape", 40});// Accessing values using [] operatorstd::cout << my_map["apple"] << std::endl;// Accessing values using at() methodstd::cout << my_map.at("banana") << std::endl;// Accessing values using find() methodauto it = my_map.find("orange");if (it != my_map.end()) {std::cout << it->second << std::endl;}// Accessing values using iteratorfor (auto it = my_map.begin(); it != my_map.end(); ++it) {std::cout << it->first << " : " << it->second << std::endl;}// Accessing values not existing in the map// using at() methodstd::cout << my_map.at("mango")<< std::endl; // This will also throw an exceptionif (my_map.find("mango") != my_map.end()) {std::cout << "exist mango in map" << std::endl;} else {std::cout << "not exist mango in map" << std::endl;}return 0;
}

直接漰溃:

map和multimap

mapmultimapunordered_mapunorder_multimap
下标(键)支持不支持(原因:因为键值可以重复)不支持

map和unorder_map的区别

链接

map的部分函数

at()参数:键
find

参数:键

成功返回元素迭代器,失败返回end()的迭代器。

成员方法功能
begin()返回指向容器中第一个(注意,是已排好序的第一个)键值对的双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
end()返回指向容器最后一个元素(注意,是已排好序的最后一个)所在位置后一个位置的双向迭代器,通常和 begin() 结合使用。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
rbegin()返回指向最后一个(注意,是已排好序的最后一个)元素的反向双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。
rend()返回指向第一个(注意,是已排好序的第一个)元素所在位置前一个位置的反向双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。
cbegin()和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。
cend()和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。
crbegin()和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。
crend()和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。
find(key)在 map 容器中查找键为 key 的键值对,如果成功找到,则返回指向该键值对的双向迭代器;反之,则返回和 end() 方法一样的迭代器。另外,如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
contains(key)注意:这个成员函数是c++20新增加的,必须是在使用C++20的情况下才能使用。
lower_bound(key)返回一个指向当前 map 容器中第一个大于或等于 key 的键值对的双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
upper_bound(key)返回一个指向当前 map 容器中第一个大于 key 的键值对的迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
equal_range(key)该方法返回一个 pair 对象(包含 2 个双向迭代器),其中 pair.first 和 lower_bound() 方法的返回值等价,pair.second 和 upper_bound() 方法的返回值等价。也就是说,该方法将返回一个范围,该范围中包含的键为 key 的键值对(map 容器键值对唯一,因此该范围最多包含一个键值对)。
empty() 若容器为空,则返回 true;否则 false。
size()返回当前 map 容器中存有键值对的个数。
max_size()返回 map 容器所能容纳键值对的最大个数,不同的操作系统,其返回值亦不相同。
operator[]map容器重载了 [] 运算符,只要知道 map 容器中某个键值对的键的值,就可以向获取数组中元素那样,通过键直接获取对应的值。
at(key)找到 map 容器中 key 键对应的值,如果找不到,该函数会引发 out_of_range 异常。
insert()向 map 容器中插入键值对。
erase()

删除 map 容器指定位置、指定键(key)值或者指定区域内的键值对。

可以是键值,也可以是迭代器:

swap()交换 2 个 map 容器中存储的键值对,这意味着,操作的 2 个键值对的类型必须相同。
clear()清空 map 容器中所有的键值对,即使 map 容器的 size() 为 0。
emplace()在当前 map 容器中的指定位置处构造新键值对。其效果和插入键值对一样,但效率更高。
emplace_hint()在本质上和 emplace() 在 map 容器中构造新键值对的方式是一样的,不同之处在于,使用者必须为该方法提供一个指示键值对生成位置的迭代器,并作为该方法的第一个参数。
count(key)在当前 map 容器中,查找键为 key 的键值对的个数并返回。注意,由于 map 容器中各键值对的键的值是唯一的,因此该函数的返回值最大为 1。

insert

源码

typedef std::pair<const _Key, _Tp>        value_type;insert(value_type&& __x){ return _M_t._M_insert_unique(std::move(__x)); }template<typename _Pair>
__enable_if_t<is_constructible<value_type, _Pair>::value, pair<iterator, bool>>
insert(_Pair&& __x)
{
......
}

insert的插入不能直接map.insert(key,value),

需要插入一个pair对,也就是必须要使用{}阔起来。

map.insert({key,value});

map的下标和解引用

其他可以进行下标和解引用的容器,解引用和下标操作结果都是取值。

但是map不同,解引用是pair对象的引用,下标才是取值。

对于下标的使用要非常注意:如果不想因为所对应的键值对不存在而创建多余键值对,就不要用下标,应该用find查找:

map的一些操作

1,删除值

2,对map进行排序

首先一定要注意map模板类的第三个模板参数,这个参数决定元素按键值升序或者降序在map中的存储方式:

默认:less<key>升序      

可设置:greater<key>降序

也可以自己定义键值比较函数,用函数名作为第三个参数


这个参数默认map 中的元素是以键值key递增存储的。

如果需要递减存储就设置第三个参数未greater<key>。

注意,key是你设置的数据的类型。

以上是初始建立map对象时设置的,如果运用过程中想要修改map容器的元素的存储顺序,怎么办:

自定义键值比较函数

详细链接

map中当key是结构体或者类时,需要重载哪些函数

看链接可知:函数对象中实现对函数调用符--小括号的重载。而map传递过去用于比较的是map的键,但是如果键是结构体或者类,那么结果或者类是比较不了的,所以这个时候需要我们自己重定义这个函数对象,重载()的时候,不是比较结构体或者类,而是比较结构体或者类中的某一个元素。

map实现按值排列存储---实现pair对存储数据

map实现不了按值存储,即使你实现了pair对按序插入,也不会按序在map中存储。我们只能将map中的pair对存储在vector中,让后自定义排序函数对pair对进行排序。

#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;typedef pair<string, int> PAIR;bool cmp_by_value(const PAIR& lhs, const PAIR& rhs) {return lhs.second < rhs.second;
}struct CmpByValue {bool operator()(const PAIR& lhs, const PAIR& rhs) {return lhs.second < rhs.second;}
};int main() {map<string, int> name_score_map;name_score_map["LiMin"] = 90;name_score_map["ZiLinMi"] = 79;name_score_map["BoB"] = 92;name_score_map.insert(make_pair("Bing",99));name_score_map.insert(make_pair("Albert",86));//把map中元素转存到vector中vector<PAIR> name_score_vec(name_score_map.begin(), name_score_map.end());sort(name_score_vec.begin(), name_score_vec.end(), CmpByValue());// sort(name_score_vec.begin(), name_score_vec.end(), cmp_by_value);for (int i = 0; i != name_score_vec.size(); ++i){cout<<name_score_vec[i].first<<name_score_vec[i].second<<endl;}return 0;
}

http://www.dtcms.com/a/353665.html

相关文章:

  • Java 使用Jna 调用 C# dll文件踩到的坑
  • SpringBoot整合Redis:从入门到实战的完整指南
  • 【Linux 小实战】自定义 Shell 的编写
  • LCD 上显示字符
  • zookeeper-集群扩缩容
  • 稳敏双态融合架构--架构师的练就
  • banner这个文件是怎么请求到后端数据的
  • Rust:引用
  • Vue-24-利用Vue3的element-plus库实现树形结构数据展示
  • Autodesk Maya 2026.2 全新功能详解:MotionMaker AI 动画、LookdevX 材质增强、USD 工作流优化
  • 在MiniOB源码中学习使用Flex与Bison解析SQL语句-第二节
  • 【Linux】正则表达式学习记录
  • FFMPEG api使用
  • 从disable_cost到disabled_nodes,最小代价预估质的飞跃
  • nestjs日志(nest-winston)
  • pyecharts可视化图表-tree:从入门到精通
  • Linux 系统调优与CPU-IO-网络内核参数调优
  • Task04: CAMEL框架中的多智能体系统(课程第三章剩余章节)
  • 大模型安全概述、LlamaFirewall
  • ESP8266:Arduino学习
  • 前端性能优化:从指标监控到全链路落地(2024最新实战指南)
  • 短视频矩阵管理软件推荐——小麦矩阵系统深度解析
  • 关于两视图相机几何关系
  • DevExpress WPF中文教程:如何将WPF数据网格绑定到本地集合?
  • 软件定义汽车(SDV)调试——如何做到 适配软件定义汽车(SDV)?(下)
  • vue新能源汽车销售平台的设计与实现(代码+数据库+LW)
  • 【Vue2✨】 Vue2 入门之旅(二):模板语法
  • Python异步编程:从理论到实战的完整指南
  • Qt---项目架构解读
  • BiLSTM-Attention分类预测+SHAP分析+特征依赖图!深度学习可解释分析,Matlab代码实现