std标准库中 map, set, unordered_map, unordered_set插入方法比较

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::pair insert( 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 
using namespace std;
int main()
{
    map my_map;
    my_map.insert(std::pair(3, 0.1));
    my_map.insert(std::pair(1, 0.2));
    my_map[2] = 0.3;
    my_map[4] = 0.4;
    for (auto& item :my_map)
        std::cout << item.first << " " << item.second << std::endl; // 输出为1.8
    return true;
}

输出结果:(遍历时按照键值从小到大输出)

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

 

 

你可能感兴趣的:(code之路)