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 #include int main() { std::map my_map; my_map["apple"] = 10; my_map.insert(std::pair("banana", 20)); my_map.insert(std::make_pair("orange", 30)); my_map.insert({"grape", 40}); // Accessing values using [] operator std::cout << my_map["apple"] << std::endl; // Accessing values using at() method std::cout << my_map.at("banana") << std::endl; // Accessing values using find() method auto it = my_map.find("orange"); if (it != my_map.end()) { std::cout << it->second << std::endl; } // Accessing values using iterator for (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 [] operator std::cout << my_map["mango"] << std::endl; // This will throw an exception if (my_map.find("mango") != my_map.end()) { std::cout << "exist mango in map" << std::endl; } return 0; } ![](https://i-blog.csdnimg.cn/direct/c0e5b1f1730a4e7b9f69421af43cf90d.png) at(): #include #include int main() { std::map my_map; my_map["apple"] = 10; my_map.insert(std::pair("banana", 20)); my_map.insert(std::make_pair("orange", 30)); my_map.insert({"grape", 40}); // Accessing values using [] operator std::cout << my_map["apple"] << std::endl; // Accessing values using at() method std::cout << my_map.at("banana") << std::endl; // Accessing values using find() method auto it = my_map.find("orange"); if (it != my_map.end()) { std::cout << it->second << std::endl; } // Accessing values using iterator for (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() method std::cout << my_map.at("mango") << std::endl; // This will also throw an exception if (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; } 直接漰溃: ![](https://i-blog.csdnimg.cn/direct/5373660a91414320b00b403a1489cb24.png) ### map和multimap |-------|-----|------------------|---------------|------------------| | | map | multimap | unordered_map | unorder_multimap | | 下标(键) | 支持 | 不支持(原因:因为键值可以重复) | | 不支持 | | | | | | | map和unorder_map的区别 [链接](https://blog.csdn.net/zou_albert/article/details/106983268?utm_source=app&app_version=5.0.1&code=app_1562916241&uLinkId=usr1mkqgl919blen "链接") ### 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)值或者指定区域内的键值对。 可以是键值,也可以是迭代器: ![](https://i-blog.csdnimg.cn/blog_migrate/1fd4b8b1d93f64e01fb20e25e78db2d9.jpeg) | | 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 value_type; insert(value_type&& __x) { return _M_t._M_insert_unique(std::move(__x)); } template __enable_if_t::value, pair> insert(_Pair&& __x) { ...... } insert的插入不能直接map.insert(key,value), 需要插入一个pair对,也就是必须要使用{}阔起来。 map.insert({key,value}); ### map的下标和解引用 其他可以进行下标和解引用的容器,解引用和下标操作结果都是取值。 但是map不同,解引用是pair对象的引用,下标才是取值。 对于下标的使用要非常注意:如果不想因为所对应的键值对不存在而创建多余键值对,就不要用下标,应该用find查找: ### map的一些操作 1,删除值 #### 2,对map进行排序 首先一定要注意map模板类的第三个模板参数,这个参数决定元素按键值升序或者降序在map中的存储方式: 默认:less\升序 可设置:greater\降序 也可以自己定义键值比较函数,用函数名作为第三个参数 ![](https://i-blog.csdnimg.cn/blog_migrate/3952487442d1e8b87d5dede31ddd1b3f.jpeg) 这个参数默认map 中的元素是以键值key递增存储的。 如果需要递减存储就设置第三个参数未greater\。 注意,key是你设置的数据的类型。 以上是初始建立map对象时设置的,如果运用过程中想要修改map容器的元素的存储顺序,怎么办: #### 自定义键值比较函数 [详细链接](https://blog.csdn.net/IIcyZhao/article/details/11906189?utm_source=app&app_version=5.0.1&code=app_1562916241&uLinkId=usr1mkqgl919blen "详细链接") #### map中当key是结构体或者类时,需要重载哪些函数 看链接可知:函数对象中实现对函数调用符--小括号的重载。而map传递过去用于比较的是map的键,但是如果键是结构体或者类,那么结果或者类是比较不了的,所以这个时候需要我们自己重定义这个函数对象,重载()的时候,不是比较结构体或者类,而是比较结构体或者类中的某一个元素。 ### map实现按值排列存储---实现pair对存储数据 map实现不了按值存储,即使你实现了pair对按序插入,也不会按序在map中存储。我们只能将map中的pair对存储在vector中,让后自定义排序函数对pair对进行排序。 #include #include #include #include #include using namespace std; typedef pair 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 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 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<

相关推荐
MonkeyKing_sunyuhua25 分钟前
什么是JSON-RPC 2.0,在项目中应该怎么使用
qt·rpc·json
雷达学弱狗28 分钟前
anaconda本身有一个python环境(base),想用别的环境就是用anaconda命令行往anaconda里创建虚拟环境
开发语言·python
燃尽余火1 小时前
Knife4j 文档展示异常的小坑
java·开发语言·spring
tan77º1 小时前
【项目】分布式Json-RPC框架 - 抽象层与具象层实现
linux·服务器·c++·分布式·tcp/ip·rpc·json
zzx_blog1 小时前
c++函数工厂实现两种方式:lambda和function
c++
mit6.8241 小时前
[pilot智驾系统] 自动驾驶守护进程(selfdrived)
linux·c++·自动驾驶
jokr_1 小时前
C++ STL 顶层设计与安全:迭代器、失效与线程安全
java·c++·安全
爬虫程序猿1 小时前
利用 Java 爬虫按关键字搜索 1688 商品详情 API 返回值说明实战指南
java·开发语言·爬虫
Bling_Bling_11 小时前
ES6新语法特性(第二篇)
开发语言·前端·es6
jokr_2 小时前
C++ 指针与引用面试深度解析
java·c++·面试