std标准库中存在 map, set, unordered_map, unordered_set这四种结构,其中map包括key 和 value 组成,set只有key(键值)。unordered_map和unordered_set是通过哈希表(hash)的形式存储数据,以适应更快速的查找。需要注意的是这四种数据结构,在存储列表中都不回出现相同的键值的。
set和unordered_set只能通过insert()函数插入数据,如果set中已经存在该键值,则insert()函数插入失败,不改变set中的值,直接返回
map和unordered_map插入数据的方法大致分为两种:insert()函数插入和直接插入:
如果map/unordered_map中已经存在key,insert()函数则插入失败,不改变map数据,直接返回;直接插入法则会改变value的值。(详细可查看下面的测试代码)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面重点介绍insert() 函数。C++ Reference是这样写的: (这里以map为例,其它等同)
std::map
::insert
std::pair
insert( const value_type& value ); (1) template< class P >
std::pairinsert( P&& value ); (2) (C++11 起) std::pair
insert( value_type&& value ); (3) (C++17 起) (4) iterator insert( iterator hint, const value_type& value );
(C++11 前) iterator insert( const_iterator hint, const value_type& value );
(C++11 起) template< class P >
iterator insert( const_iterator hint, P&& value );(5) (C++11 起) iterator insert( const_iterator hint, value_type&& value );
(6) (C++17 起) template< class InputIt >
void insert( InputIt first, InputIt last );(7) void insert( std::initializer_list
ilist ); (8) (C++11 起) insert_return_type insert(node_type&& nh);
(9) (C++17 起) iterator insert(const_iterator hint, node_type&& nh);
(10) (C++17 起) 若容器尚未含有带等价关键的元素,则插入元素到容器中。
1-3) 插入
value
。重载 (2) 等价于 emplace(std::forward(value)) ,且仅若 std::is_constructible
::value == true 才参与重载决议。 4-6) 插入
value
到尽可能接近,恰好前于(C++11 起)hint
的位置。重载 (4) 等价于 emplace_hint(hint, std::forward(value)) ,且仅若 std::is_constructible
::value == true 才参与重载决议。 7) 插入来自范围
[first, last)
的元素。若范围中的多个元素拥有比较等价的关键,则插入哪个元素是未指定的(待决的 LWG2844 )。8) 插入来自 initializer_list
ilist
的元素。若范围中的多个元素拥有比较等价的关键,则插入哪个元素是未指定的(待决的 LWG2844 )。9) 若
nh
是空的结点把柄,则不做任何事。否则插入nh
所占有的元素到容器,若容器尚未含有拥有等价于 nh.key() 的关键的元素。若nh
非空且 get_allocator() != nh.get_allocator() 则行为未定义。10) 若
nh
是空的结点把柄,则不做任何事并返回尾迭代器。否则,插入nh
所占有的元素到容器,若容器尚未含有拥有等价于 nh.key() 的关键的元素,并返回指向拥有等于 nh.key() 的关键的元素的迭代器(无关乎插入成功还是失败)。若插入成功,则从nh
移动,否则它保持该元素的所有权。元素被插入到尽可能接近正好先于hint
的位置。若nh
非空且 get_allocator() != nh.get_allocator() 则行为未定义。没有迭代器或引用被非法化。若插入成功,则在结点把柄保有元素时获得的指向该元素的指针和引用被非法化,而在提取前获得的指向元素的指针和引用变得合法。 (C++17 起)
参数
hint -
用作搜索开始位置的建议的迭代器
(C++11 前) 指向将插入新元素到其前的位置的迭代器
(C++11 起) value - 要插入的值 first, last - 要插入的元素范围 ilist - 插入值来源的 initializer_list nh - 兼容的结点把柄 类型要求 - InputIt
必须满足遗留输入迭代器 (LegacyInputIterator) 的要求。返回值
1-3) 返回由指向被插入元素的迭代器(或阻止插入的元素的迭代器)和指代插入是否发生的 bool 组成的 pair 。
4-6) 返回指向被插入元素的迭代器,或指向阻止插入的元素的迭代器。
7-8) (无)
9) 返回
insert_return_type
,其成员初始化如下:若nh
为空,则inserted
为false
,position
为 end() ,而node
为空。否则发生插入,inserted
为true
,position
指向被插入元素,而node
为空。若插入失败,则inserted
为false
,node
拥有nh
的先前值,而position
指向拥有等价于 nh.key() 的关键的元素。10) 若
nh
为空则为尾迭代器,若插入发生则为指向被插入元素的迭代器,而若插入失败则为指向拥有等价于 nh.key() 的关键的元素的迭代器。
简而言之,如果数组列表中没有相同的key值,则成功插入元素。如果已经存在相同的key值,则插入失败,不会改变数组列表。调用insert()函数后返回两个量:1. 插入成功则返回插入的这个元素再数组里面的迭代器,如已经存在相同的key值插入不成功,则返回已有的那个key值的迭代器(也就是阻止插入的元素的迭代器),2. 插入是否成功的标志位。
下面,以unordered_map为例,测试元素插入方法:
#include
#include
using namespace std;
int main()
{
unordered_map hash_map;
hash_map.insert(std::pair(1, 0.1));
hash_map.insert(std::pair(2, 0.2));
//auto的类型为:std::pair::iterator, bool>
auto flag1 = hash_map.insert(std::pair(3, 0.3));
auto flag2 = hash_map.insert(std::pair(3, 0.5));
std::cout << hash_map[3] << std::endl; // 输出为0.3
std::cout << flag1.second << " " << flag1.first->first << " " << flag1.first->second << std::endl;
std::cout << flag2.second << " " << flag2.first->first << " " << flag2.first->second << std::endl;
hash_map[2] = 1.5; //直接插入方法
hash_map[2] = 1.8;
std::cout << hash_map[2] << std::endl; // 输出为1.8
return true;
}
输出结果:
0.3
1 3 0.3
0 3 0.3
1.8
因此我们在做插入数据的时候一定要特别注意,不同的插入方法使用不同的环境中,需要谨慎!!!
另外,需要注意的是,map和set插入数据后,插入的元素会按照key值进行排序存储,而unordered_map和unordered_set既不是排序存储,也不是按照插入顺序存储,二是按照hash表建立规则进行的,具体遍历排列方式还需要学习一下哈希表的知识再来补充。这里以map和unordered_map为例测试:
#include
#include
输出结果:(遍历时按照键值从小到大输出)
1 0.2
2 0.3
3 0.1
4 0.4
#include
#include
using namespace std;
int main()
{
unordered_map hash_map;
hash_map.insert(std::pair(1, 0.3));
hash_map.insert(std::pair(6, 0.2));
hash_map.insert(std::pair(3, 0.5));
hash_map.insert(std::pair(2, 0.1));
for (auto& item :hash_map )
std::cout << item.first << " " << item.second << std::endl; // 输出为1.8
return true;
}
输出结果:
2 0.1
3 0.5
1 0.3
6 0.2