写在前面:
标准库容器类型:
1、顺序容器
比如:vector、list、deque、forward_list(C++11)等。
2、关联容器
关联式容器也是用来存储数据的,与顺序容器不同的是,其里面存储的是
两者之间的差别: 关联容器通过键(key)存储和读取元素 而顺序容器则通过元素在容器中的位置存储和访问元素且关联式容器大部分和顺序容器相同 比较特别的地方就是关联容器支持键的使用 。
键值对
用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值, value表示与key对应的信息
关联容器共享大部分顺序容器的操作 但是关联容器不提供
front、push_front、pop_front、back、push_back 以及pop_pack操作
但关联容器可以支持
begin、end、rbegin、rend操作
同时关联容器还有以下和顺序容器公共的构造函数
C
c; //创建一个空的容器
Cc1(c2); //用c2来拷贝构造c1 ,前提是c2必须和c1的类型相同
Cc(b,e); //将序列中的元素复制到c中 b和e是表示序列的迭代器
关联容器支持通过键来高效地查找和读取元素 两个基本的关联容器的类型是
map set
map 的元素以 键 – 值 (key --value) 对的形式组织, 键用在map中的索引 而值表示所存储和读取的数据
set 仅包含一个值 并有效的支持某个值是否存在的查询
注:
如果希望有效的存储不同值的集合 那么使用set容器比较合适
而 map容器则更使用于需要存储、修改 每个键所关联的值的情况
比如说map可以用来实现一个简单的字典
map 和set 类型的对象所包含的元素都具有不同的键值 不允许为同一个键 添加第二个元素 也就是一个key 不能对应两个不同的value
如果一个键必须对应多个实例 则需要使用multimp 或multiset
multimap :支持同一个键多次出现的map类型
multiset :支持同一个键多次出现的set类型
关联容器也支持很多顺序容器也提供相同的操作 此外 还提供 管理或只用键的特殊操作
map | 关联数组 元素通过键来存取和读取 |
---|---|
set | 大小可变的集合,支持通过键实现的快速读取 |
multimap | 支持同一个键多次出现的map类型 |
multiset | 支持同一个键多次出席那的set类型 |
这次的博客主要来整理map的相关知识要点!
1.map是关联容器,它按照特定的次序(按照key来比较)存储由键–key和值–value组合而成的元素。 (有序)
2. 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的内容。键值 key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起, 为其取别名称为pair: typedef pair value_type;
3.在内部,map中的元素总是按照键值key进行比较排序的。
4. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行 直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
5.map支持下标访问符,即在[ ]中放入key,就可以找到与key对应的value。
6. map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。
注意:
关于 pair 对象就不再这里重复的介绍了,稍微的提一下
pair 也是一种类模板 ,这个类将一对值耦合在一起,这些值可能是不同类型的 ,单个值可以通过其公共成员 first 和 second 访问。
因此这里说的 key 和 value 也就是 pair 对象中的 公共成员 first 和 second
脑子里记住这个不是地图了哟!
map 是 "键–值对"的集合。
map类型通常可理解为关联数组;
可使用 "键"作为下标来获取一个值,正如内置数组类型一样 而关联的本质在于元素的值与某个特定的键相关联,而并非通过元素在数组中的位置来获取。
key: 键值对中key的类型
T: 键值对中value的类型
Compare: 比较器的类型,map中的元素是按照key来比较的,缺省情况下按照 less (小于)来比较,一般情况 下(内置类型元素)该参数不需要传递,如果无法比较时(自定义类型),需要用户自己显式传递比较规则 (一般情况下按照函数指针或者仿函数来传递)
Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的空间配置器 注意:在使用map时,需要包含头文件。
关联容器中的元素由它们的key作为引用而不是他们在容器中的绝对位置
容器中所有的元素总是有着严格的顺序,所有插入的元素都按此顺序都有确定的位置
容器中的任何两个元素都不能具有等效的key. 也就是key不能相同
要使用 map 对象,则必须包含 map 头文件。在定义 map 对象时,必须分 别指明"键"和"值"的类型(value type)
例如 :定义键和值都是string 类型的 map对象。
#include
#include
int main()
{
map<string,string> m;//键索引是 string 类型的 关联的值是 string 类型的
return 0;
}
________________________________函数声明 | __________________________说明 |
---|---|
map |
创建一个名为 m 的空 map 对象,其键和值的类型分别为 k 和 v |
map |
创建 m2 的副本 m也就是用m2来拷贝构造m,m 与 m2 必须有相同的键类型和值类型 |
map |
使用存储迭代器 b 和 e 标记的范围内所有 元素的副本来创建m。元素的类型必须能转换为 pair |
示例:
void Test1()
{
map<string,string>m;//创建一个空的map对象
m.insert(pair<string,string>("helloworld!","你好世界!"));
//插入数据
map<string, string> m1(m);//拷贝构造
map<string, string> m2(m.begin(), m.end());//使用迭代器进行构造
for (auto e : m)
{
cout << e.first << " " << e.second << endl;
}
for (auto e : m1)
{
cout << e.first << " " << e.second << endl;
} for (auto e : m2)
{
cout << e.first << " " << e.second << endl;
}
}
函数声明 功能简介
iterator begin () | 返回第一个元素的位置 |
---|---|
iterator end () | 返回最后一个元素的下一个位置 |
const_iterator begin () const | 返回第一个元素的const迭代器 |
const_iterator end () const | 返回最后一个元素下一个位置的const迭代器 |
reverse_iterator rbegin() | 返回第一个元素位置的反向迭代器即rend |
reverse_iterator rend() | 返回最后一个元素下一个位置的反向迭代器即 rbegin |
const_reverse_iterator rbegin() const | 返回第一个元素位置的const反向迭代器即rend |
const_reverse_iterator rend() const | 返回最后一元素下一个位置的反向迭代器即rbegin |
大家会发现其实这个和我们之前的vector的迭代器没有多大的差别不过就是多了一个 const 的反向迭代器,用法和vector是差不多的。
做几个简单的示例:假设map对象里的值,我们事先是已经插入好了的。
map<int, string>m;
m.insert(pair<int, string>(1001, "小明"));
m.insert(pair<int, string>(1003, "小红"));
m.insert(pair<int, string>(1002, "小花"));
m.insert(pair<int, string>(1000, "小花"));
Test2(m);
cout << "普通正向迭代器遍历" << endl;
map<int, string>::iterator mite = m1.begin();
while (mite != m1.end())
{
cout << mite->first << " " << mite->second << endl;
++mite;
}
注意:
这里再对map对象的 first 和 second 访问是使用的是 " - >" --箭头操作符
这里大家会发现map里面的是已经排好序了的,会默认把键值小的排在前面,是一个升序的排列,相对于int类型的值就会直接进行比较而 string 类型或者别的是按ASCCI码来比较如以下:
cout << "普通反向迭代器遍历" << endl;
map<int, string>::reverse_iterator rmite = m1.rbegin();
while (rmite != m1.rend())
{
rmite->second = "李飞";
cout << rmite->first << " " << rmite->second << endl;
++rmite;
}
cout << "const迭代器遍历" << endl;
map<int, string>::const_iterator cite = m1.begin();
while (cite != m1.end())
{
cout << cite->first << " " << cite->second << endl;
++cite;
}
cout << "const反向迭代器遍历" << endl;
map<int, string>::const_reverse_iterator crite = m1.rbegin();
while (crite != m1.rend())
{
cout << crite->first << " " << crite->second << endl;
++crite;
}
其实这样遍历还是比较麻烦的,相比有两种比较简约而又方便的遍历方式推荐给大家,但是他们的底层还是使用的相关迭代器进行实现的
void Test4(map<int,string> &m)
{
cout << "范围 for遍历" << endl;
for (auto e : m)
{
cout << e.first << " " << e.second << endl;
}
}
void Test5(map<int, string> &m)
{
cout << "auto关键字的使用" << endl;
auto mite = m.begin();
while (mite != m.end())
{
cout <<mite->first << " " << mite->second << endl;
++mite;
}
}
函数声明 | 功能简介 |
---|---|
pair |
在map中插入键值对x,注意x是一个键值对,返回 值也是键值对:iterator代表新插入元素的位置, bool代表释放插入成功 |
iterator insert ( iterator position, const value_type& x ) | 在position位置插入值为x的键值对,返回该键值对 在map中的位置,注意:元素不一定必须插在 position位置,该位置只是一个参考 |
template void insert ( InputIterator first, InputIterator last ) | 在map中插入[first, last)区间中的元素 |
void erase ( iterator position ) | 删除position位置上的元素 |
size_type erase ( const key_type& x ) | 删除键值为x的元素 |
void erase ( iterator first, iterator last ) | 删除[first, last)区间中的元素 |
void swap ( map |
交换两个map中的元素 |
void clear ( ) 将map中的元素清空 | iterator find ( const key_type& x ) |
const_iterator find ( const key_type& x ) const | 在map中插入key为x的元素,找到返回该元素的位 置的const迭代器,否则返回cend |
size_type count ( const key_type& x ) const | 返回key为x的键值在map中的个数,注意map中 key是唯一的,因此该函数的返回值要么为0,要么 为1,因此也可以用该函数来检测一个key是否在 map中 |
这里的插入肯定是插入一个 pair 对象,那么请看示例;
map<int, string> m;
pair<int, string> p1(2, "two");
m.insert(pair<int, string>(1, "one"));
m.insert(p1);
for (auto e : m)
{
cout << e.first <<" "<<e.second << endl;
}
注意
在一个map对象中 key 的值是唯一的,是不允许插入两个相同的 key ,相同的key 所对应的value也无法插入
map<int, string>m;
m.insert(pair<int, string>(1, "one"));
m.insert(pair<int, string>(2, "two"));
m.insert(pair<int, string>(3, "three"));
auto a = m.begin();
m.erase(a);//删除迭代器位置的元素
m.erase(3);//删除 key 为3的元素 即 first=3 的数据
函数声明 | 功能简介 |
---|---|
bool empty ( ) const | 检测map中的元素是否为空,是返回true,否则 返回false |
size_type size() const | 返回map中有效元素的个数 |
mapped_type& operator[] (const key_type& k) | 返回去key对应的value |
注意:
虽然 key 不能修改但是 value是可以修改的,也可以通过 [ key ]来访问对应的 value 或者修改:
如: