【C++】STL map 与 multimap 用法和区别
参考:
- https://blog.csdn.net/shuzfan/article/details/53115922
- https://www.nhooo.com/cpp/cpp-map-swap-function.html
- https://blog.csdn.net/qq_34106574/article/details/86721916
- https://blog.csdn.net/zhongguoren666/article/details/8463249
一、std::map
1. 概述:
STL是标准C++系统的一组模板类,使用STL模板类最大的好处就是在各种C++编译器上都通用。
在STL模板类中,用于线性数据存储管理的类主要有vector、 list,、map 等等。
C++中map提供的是一种键值对容器,里面的数据都是成对出现的,每一对中的第一个值称之为关键字(key),每个关键字只能在map中出现一次;第二个称之为该关键字的对应值。
2. 用法:
(1)声明:
//头文件
#include <map>
//注意,STL头文件没有扩展名.hmap<int, string> ID_Name;// 使用{}赋值是从c++11开始的,因此编译器版本过低时会报错,如visual studio 2012
map<int, string> ID_Name = {{ 2015, "Jim" },{ 2016, "Tom" },{ 2017, "Bob" } };
(2)插入操作:
- 使用[ ]进行单个插入:
map<int, string> ID_Name;// 如果已经存在键值2015,则会作赋值修改操作,如果没有则插入
ID_Name[2015] = "Tom";
- 使用insert进行单个和多个插入:
insert共有4个重载函数:
// 插入单个键值对,并返回插入位置和成功标志,插入位置已经存在值时,插入失败
pair<iterator,bool> insert (const value_type& val);//在指定位置插入,在不同位置插入效率是不一样的,因为涉及到重排
iterator insert (const_iterator position, const value_type& val);// 插入多个
void insert (InputIterator first, InputIterator last);//c++11开始支持,使用列表插入多个
void insert (initializer_list<value_type> il);
下面是具体使用示例:
#include <iostream>
#include <map>int main()
{std::map<char, int> mymap;// 插入单个值mymap.insert(std::pair<char, int>('a', 100));mymap.insert(std::pair<char, int>('z', 200));//返回插入位置以及是否插入成功std::pair<std::map<char, int>::iterator, bool> ret;ret = mymap.insert(std::pair<char, int>('z', 500));if (ret.second == false) {std::cout << "element 'z' already existed";std::cout << " with a value of " << ret.first->second << '\n';}//指定位置插入std::map<char, int>::iterator it = mymap.begin();mymap.insert(it, std::pair<char, int>('b', 300)); //效率更高mymap.insert(it, std::pair<char, int>('c', 400)); //效率非最高//范围多值插入std::map<char, int> anothermap;anothermap.insert(mymap.begin(), mymap.find('c'));// 列表形式插入anothermap.insert({ { 'd', 100 }, {'e', 200} });return 0;
}
(3)取值:
Map中元素取值主要有at和[ ]两种操作,at会作下标检查,而[]不会。
map<int, string> ID_Name;//ID_Name中没有关键字2016,使用[]取值会导致插入
//因此,下面语句不会报错,但打印结果为空
cout<<ID_Name[2016].c_str()<<endl;//使用at会进行关键字检查,因此下面语句会报错
ID_Name.at(2016) = "Bob";
(4)容量查询:
// 查询map是否为空
bool empty();// 查询map中键值对的数量
size_t size();// 查询map所能包含的最大键值对数量,和系统和应用库有关。
// 此外,这并不意味着用户一定可以存这么多,很可能还没达到就已经开辟内存失败了
size_t max_size();// 查询关键字为key的元素的个数,在map里结果非0即1
size_t count( const Key& key ) const; //
(5)迭代器:
共有八个获取迭代器的函数:begin, end, rbegin, rend 以及对应的 cbegin, cend, crbegin, crend。
二者的区别在于:后者一定返回 const_iterator,而前者则根据map的类型返回iterator 或者 const_iterator。const情况下,不允许对值进行修改。如下面代码所示:
map<int,int>::iterator it;map<int,int> mmap;
const map<int,int> const_mmap;it = mmap.begin(); //iterator
mmap.cbegin(); //const_iteratorconst_mmap.begin(); //const_iterator
const_mmap.cbegin(); //const_iterator
返回的迭代器可以进行加减操作,此外,如果map为空,则 begin = end。
(6)删除交换:
- 删除:
// 删除迭代器指向位置的键值对,并返回一个指向下一元素的迭代器
iterator erase( iterator pos )// 删除一定范围内的元素,并返回一个指向下一元素的迭代器
iterator erase( const_iterator first, const_iterator last );// 根据Key来进行删除,返回删除的元素数量,在map里结果非0即1
size_t erase( const key_type& key );// 清空map,清空后的size为0
void clear();
//clear()就相当于enumMap.erase(enumMap.begin(), enumMap.end());
示例:
enumMap.erase(1); //删掉关键字“1”对应的条目
enumMap.erase(enumMap.begin()); //删掉第一个条目
enumMap.erase(enumMap.begin(), enumMap.begin() + 1); //删掉起始的两个条目
- 交换:
交换两个map的内容,但是两个map必须是相同类型的,尽管大小可能会有所不同。
// 就是两个map的内容互换
void swap( map& other );
示例:
1.
#include <iostream>
#include <map>using namespace std;int main(void) {map<char, int> m1 = {{'a', 1},{'b', 2},{'c', 3},{'d', 4},{'e', 5},};map<char, int> m2;m2.swap(m1);cout << "Map包含以下元素" << endl;for (auto it = m2.begin(); it != m2.end(); ++it)cout << it->first << " = " << it->second << endl;return 0;
}//输出:
Map包含以下元素
a = 1
b = 2
c = 3
d = 4
e = 5
在上面的示例中,Map m1具有五个元素,而m2为空。当您将m1交换为m2时,m1的所有元素都将交换为m2。
2.
#include <iostream>
#include <string>
#include <map>using namespace std;void show(const char *msg, map<string, int> mp);int main() {map<string, int> m1, m2;m1.insert(pair<string, int>("A", 100));m1.insert(pair<string, int>("G", 300));m1.insert(pair<string, int>("B", 200));// 交换m1和m2的内容。cout << "交换m1和m2。\n";m1.swap(m2);show("Contents of m2: ", m2);show("Contents of m1: ", m1);// Clear m1.m1.clear();if(m1.empty()) cout << "m1 为空.";return 0;
}// 使用迭代器显示map<string, int>的内容。
void show(const char *msg, map<string, int> mp) {map<string, int>::iterator itr;cout << msg << endl;for(itr=mp.begin(); itr != mp.end(); ++itr)cout << " " << itr->first << ", " << itr->second << endl;cout << endl;
}//输出:
交换m1和m2。
m2内容: A, 100B, 200G, 300
m1内容:
m1 为空.
在上面的示例中,Map m1的内容被交换到Map m2,并且在交换Map m1 后已被清除。
(7)顺序比较:
// 比较两个关键字在map中位置的先后
key_compare key_comp() const;
示例:
map<char,int> mymap;
map<char,int>::key_compare mycomp = mymap.key_comp();mymap['a']=100;
mymap['b']=200;
mycomp('a', 'b'); // a排在b前面,因此返回结果为true
(8)查找:
- find(key):
// 关键字查询,找到则返回指向该关键字的迭代器,否则返回指向end的迭代器
// 根据map的类型,返回的迭代器为 iterator 或者 const_iterator
iterator find (const key_type& k);
const_iterator find (const key_type& k) const;
示例:
std::map<char,int> mymap;
std::map<char,int>::iterator it;mymap['a']=50;
mymap['b']=100;
mymap['c']=150;
mymap['d']=200;it = mymap.find('b');
if (it != mymap.end())mymap.erase (it); // b被成功删除/*find的时候注意key的数据类型,最好用能消除数据类型差异的key,否则可能会出现强制转换后仍找不到的情况。
需要说明的是iterator, begin(), end()是STL模板类的一个通用概念,操作方法也大同小异;
通过map对象的方法获取的iterator数据类型是一个std::pair对象,包括两个数据 iterator.first 和 iterator.second 分别代表关键字和存储的数据 */
- equal_range(key):
iterator map_name.equal_range(key)
equal_range
是C++ STL中的一种二分查找的算法,试图在已排序的[first,last)中寻找value,它返回一对迭代器i和j,其中i是在不破坏次序的前提下,value可插入的第一个位置(亦即lower_bound
),j则是在不破坏次序的前提下,value可插入的最后一个位置(亦即upper_bound
),因此,[i,j)内的每个元素都等同于value,而且[i,j)是[first,last)之中符合此一性质的最大子区间。
equal_range
根据键值,返回一对迭代器的pair对象。如果该键值在容器中存在,则pair对象中的第一个迭代器指向该键关联的第一个实例,第二个迭代器指向该键关联的最后一个实例的下一位置。如果找不到匹配的元素,则pair对象中的两个迭代器都将指向此键应该插入的位置。总之,equal_range
返回迭代器位置区间 [ lower_bound, upper_bound )
。
算法lower_bound
返回区间A的第一个迭代器,算法upper_bound
返回区间A的最后一个元素的下一个位置,算法equal_range
则是以pair
的形式将两者都返回。
示例:
#include <iostream>
#include <map>
using namespace std;int main ()
{map<char,int> mymap;pair<map<char,int>::iterator,map<char,int>::iterator> ret;mymap['a']=10;mymap['b']=20;mymap['c']=30;ret = mymap.equal_range('b');cout << "lower bound points to: ";cout << ret.first->first << " => " << ret.first->second << endl;cout << "upper bound points to: ";cout << ret.second->first << " => " << ret.second->second << endl;return 0;
}//运行结果:
lower bound points to: 'b' => 20
upper bound points to: 'c' => 30
(9)操作符:
operator:==
!=
<
<=
>
>=
注意:对于==
运算符, 只有键值对以及顺序完全相等才算成立。
(10)遍历:
#include<map>
#include<string>
#include<iostream>
using namespace std;int main()
{map<string,int> m;m["a"]=1;m["b"]=2;m["c"]=3;map<string,int>::iterator it;for(it=m.begin();it!=m.end();++it)cout<<"key: "<<it->first <<" value: "<<it->second<<endl;return 0;
}
map<string,int>::iterator it; //定义一个迭代指针it。
// it->first 为索引键值,it->second 为值。
在对象中应用时,最好在析构函数中要调用它的clear方法,例如:
class a{map<int,int> m;~a(){m.clear();}
}
二、map 与 multimap 的区别:
map 与 multimap 都是存储key-value(键-值 对)类型的容器。
不同之处在于:map只允许key与value一一对应;multimap一个key可对应多个value。
示例:
以下不作特别说明,适用于map的都适用于multimap:
#include <opencv2/opencv.hpp>
#include <map>
#include <iostream>
#include <algorithm> // std::sortusing namespace std;//打印函数可写成模板//打印函数 printfA
void printfA(map<vector<int>, int> vec_)
{for (std::map<std::vector<int>, int>::iterator it = vec_.begin(); it != vec_.end(); it++){std::cout << it->first[0] << " " << it->first[1] << " " << it->first[2] << " " << it->second << std::endl;}cout << "容积 = " << vec_.size() << endl;
}//打印函数 printfB
void printfB(multimap<string, int> vec_)
{for (multimap<string, int>::iterator it = vec_.begin(); it != vec_.end(); it++){std::cout << it->first << " " << it->second << std::endl;}cout << "容积 = " << vec_.size() << endl;
}int main()
{//声明,定义std::map<int, std::string> m;m[3] = "h1";m[0] = "what";// 构建 key-valuem.insert(std::pair<int, std::string>(2, "love you"));std::cout << m[0].c_str() << std::endl;//这里数字 不是索引值了std::cout << m[3].c_str() << std::endl;std::cout << m[4].c_str() << std::endl;std::cout << m[2].c_str() << std::endl; // 会产生一个新的元素,即m[2] = ""m[6] = string("slam2345");std::cout << m.size() << std::endl; // 5//遍历for (std::map<int, std::string>::iterator it = m.begin(); it != m.end(); it++)std::cout << it->first << ", " << it->second.c_str() << std::endl;std::vector<int> pointTemp;std::map<std::vector<int>, int> vecA;for (int y = 0; y < 4; y++){for (int x = 0; x < 4; x++){pointTemp.push_back(y);pointTemp.push_back(x);pointTemp.push_back(x + y);//插入vecA.insert(std::pair<std::vector<int>, int>(pointTemp, (y * 4 + x + 1)));pointTemp.clear();}}printfA(vecA);
【注意】区分map与multimap:
- 两者都会自动排序;
- multimap插入不会覆盖已有键值对(对于map若有相同key,则拒绝插入)。
//***************************************************************************************************
//<1>插入返回值 判定是否插入成功//带插入数据vector<int> pointTemp_ = { 1,2,3 }; // Insert方法不能覆盖,如果键已经存在,则插入失败;【注意插入位置,是自动排序】int a1 = 4;//判定插入是否成功pair< map<vector<int>, int>::iterator, bool> isInsertOK;//注意这里声明isInsertOK = vecA.insert(pair<vector<int>, int>(pointTemp_, a1));cout << "插入成功? " << isInsertOK.second << endl;//打印printfA(vecA);//***************************************************************************************************
//<2>map对象的拷贝构造与赋值map<vector<int>, int> vecB(vecA); //拷贝构造map<vector<int>, int> vecC;vecC = vecA;vecC.swap(vecA);//***************************************************************************************************
//<3>查找map<string, int> vecD;// 你以为按照下面初始化 vecD,他的size会是5? 由于insert方法不能覆盖,所以我们将map 改成 multimapvecD.insert(pair<string, int>((string)"china", 1));vecD.insert(pair<string, int>((string)"china", 2));//拒绝插入vecD.insert(pair<string, int>((string)"china", 3));//拒绝插入vecD.insert(pair<string, int>((string)"english", 1));vecD.insert(pair<string, int>((string)"english", 2));//拒绝插入multimap<string, int> vecE;vecE.insert(make_pair((string)"china", 1));vecE.insert(make_pair((string)"china", 1));//允许插入vecE.insert(make_pair((string)"china", 3));//允许插入vecE.insert(make_pair((string)"china", 4));//允许插入vecE.insert(make_pair((string)"china", 5));//允许插入vecE.insert(make_pair((string)"english", 1));vecE.insert(make_pair((string)"english", 2));//允许插入vecE.insert(make_pair((string)"america", 1));vecE.insert(make_pair((string)"america", 2));//允许插入vecE.insert(make_pair((string)"america", 3));//允许插入cout << "multimap 初始化" << endl;cout << "vecE所有元素"<<endl;printfB(vecE);//查找区间multimap<string, int> ::iterator it1 = vecE.lower_bound("china"); //指向vecE中第一个等于键值 “china”对应的元素multimap<string, int> ::iterator it2 = vecE.upper_bound("china"); //指向vecE中第一个大于键值 “china”对应的元素cout << it1->first << " " << it1->second << endl;cout << it2->first << " " << it2->second << endl;// 等于 = lower_bound + upper_boundpair<multimap<string, int>::iterator, multimap<string, int>::iterator > it3 = vecE.equal_range("china");map<string, int>::iterator it4 = it3.first;map<string, int>::iterator it5 = it3.second;//查找key = “china”键值对的个数int iCount = vecE.count("china");//查找key = “china”对应键值对multimap<string, int>::iterator it6 = vecE.find("china");//***************************************************************************************************
// <4>删除multimap<string, int>::iterator itBegin = vecE.begin();// 删除 vecE 前面三个元素 与 后面 三个元素// 在改善特征点匹配算法中有实践int index = 0;int vecA_size = vecE.size();//删除(自定义删除任何元素)for (multimap<string, int>::iterator it_ = vecE.begin(); it_ != vecE.end(); ){//<1>法1//vecE.erase(it_++);//<2>法2if ((0<=index)&&(index<=2)){it_ = vecE.erase(it_);//这样写,防止指针失效}else if (((vecA_size - 3) <= index) && (index <= (vecA_size - 1))){it_ = vecE.erase(it_);}else{it_++;}++index;}//删除multimap中key = "english"的 所有 元素vecE.erase("english");cout << "vecE删除key = english的 所有 元素 " << endl;printfB(vecE);//删除所有元素multimap<string, int>::iterator itBegin_ = vecE.begin();multimap<string, int>::iterator itEnd_ = vecE.end();vecE.erase(itBegin_, itEnd_);//bool isEmpty = vecE.empty();if (vecE.empty()){cout << "vecE已经被清空" << endl;}return 0;
}
【C++】STL map 与 multimap 用法和区别相关推荐
- C++ STL map和multimap的简单使用
#include <iostream> #include <map> using namespace std;typedef pair<int,double> Cu ...
- STL 之map,multimap
头文件: #include <map> map和multimap的唯一区别:map中不可以包含重复键值,而multimap中可以. 构造方法 mType<type1,type2> ...
- C++ 笔记(24)— STL map 类(map实例化、插入、查找、删除)
1. STL 映射类简介 map 和 multimap 是键-值对容器,支持根据键进行查找,区别在于,后者能够存储重复的键,而前者只能存储唯一的键. 为了实现快速查找, STL map 和 multi ...
- c++中map、multimap、unordered_map、unordered_multimap的区别
前言: c++的各种容器使用的时候很方便,但是如果作为一个初学者,看到一堆库要记住也是很头疼的,而且很多库名称会很相似,所以我们要很好的使用这些库的时候,我们需要了解清楚它们底层实现的原理,这样我们使 ...
- c++STL容器的Map和multimap
STL容器的Map和multimap map/multimap的简介 map/multimap对象的默认构造 map的插入与迭代器 迭代器遍历 map对象的拷贝构造与赋值 map的大小 map的删除 ...
- C++STL笔记(九):map和multimap详解
--一个华科大差生的12年程序员工作总结 相关博文:<Essential C++>笔记之关联容器map的使用总结 相关博文:C++<STL和泛型编程>容器不带/带有成员函数总结 ...
- C++ map容器和multimap容器(STL map容器)
目录 1. 关联容器和map容器概述 2. map容器 2.1 map的创建以及初始化列表 2.2 map容器的一般常用属性(方法) 2.3 插入数据 2.4 数据的访问和遍历 2.5 数据的删除 2 ...
- Collection,List,Set和Map用法和区别
Collection,List,Set和Map用法和区别 原创 2009年12月22日 17:05:00 标签: list / hashmap / vector / iterator / object ...
- STL中 map 和 multimap
1. 所在头文件<map>. 命名空间std, 声明如下: 1 namespace std{ 2 template <class Key,class T, 3 class Compa ...
最新文章
- 深度学习多变量时间序列预测:GRU算法构建时间序列多变量模型预测交通流量+代码实战
- C#应用NPOI实现导出EXcel表格中插入饼状图(可实现动态数据生成)
- asp.net多图片上传案例_会计小明的故事-成本核算案例篇
- python做动态数据采集仪代理_python做监控数据采集,怎么做.
- 剑指offer java 博客_Java--剑指offer(10)
- 女员工采购电影票抽中黄金 老板:必须上交 不上交就开除
- 2万字总结《MybatisPlus—为简化开发而生》
- 人生轨迹的改变,首要在于思维方式的改变。--转贴 CSDN.NET公司内部论坛:迈向成功的“脑力操”...
- 多用户访问SSAS cube权限设置
- ps2018 html面板,28组经典PS 2018插件合集
- Atitit.每周末总结 于每周一计划日程表 流程表 v8 -------------import 上周遗漏日志补充 检查话费 检查流量情况 Crm问候 Crm表total and 问候
- GIT GUI(git的可视化工具)
- linux软路由 iptv,LEDE x64软路由实现任意网口观看上海电信4K IPTV或上网
- BT Openreach批发FTTP网络推出千兆宽带服务
- 基于AFD驱动的进程流量控制
- 使用Python及SMTP协议发送邮件(以163邮箱为例)
- java list 时间排序吗_java collection.sort()根据时间排序list | 学步园
- 一个导致ListView中item内容全部重复的可能原因,有点让我啼笑皆非
- File::Stamped 时间戳log文件
- 测试管理之--团队管理和建设