c++11: The difference between std::map and std::unordered_map (hash map)

table of Contents

1、std::map

2、std::unordered_map


The essential difference is that std::map uses a red-black tree at the bottom , while std::unordered_map uses a hash map .

1、std::map

Header file: <map>

Class declaration:

template<
    class Key,
    class T,
    class Compare = std::less<Key>,
    class Allocator = std::allocator<std::pair<const Key, T> >
> class map;

namespace pmr { //c++17起
    template <class Key, class T, class Compare = std::less<Key>>
    using map = std::map<Key, T, Compare,
                         std::pmr::polymorphic_allocator<std::pair<const Key,T>>>
}

std::map is an ordered key-value pair container, and the keys of its elements are unique. Use the compare function Compare to sort the keys. Search, remove, and insert operations have logarithmic complexity. The map is usually implemented as a red-black tree .

Where the compare concept is used in each standard library, the uniqueness is tested with an equivalence relationship. Inaccurately speaking, if two objects a and b are not less than each other than each other: !comp(a, b) && !comp(b, a), they are considered equivalent (not unique).

std::map meets the requirements of Container, AllocatorAwareContainer, AssociativeContainer and ReversibleContainer.

Member function

(Constructor) Construction  map
(public member function)

(Destructor)

Destruction  map
(public member function)

operator=

Assign to the container
(public member function)

get_allocator

Return the relevant allocator
(public member function)

Element access

at

(C++11)

Access the specified element, while checking out of bounds
(public member function)

operator[]

Access or insert the specified element
(public member function)

Iterator

start start

(C++11)

Returns an iterator to the beginning
(public member function)

endcend

(C++11)

Returns an iterator to the end
(public member function)

rbegincrebegin

(C++11)

Return a reverse iterator to the beginning
(public member function)

r endcrend

(C++11)

Return a reverse iterator to the end
(public member function)

capacity

empty

Check if the container is empty
(public member function)

size

Returns the number of elements contained
(public member function)

max_size

Returns the maximum number of elements that can be accommodated
(public member function)

modifier

clear

Clear content
(public member function)

insert

Insert element or node (since C++17)
(public member function)

insert_or_assign

(C++17)

Insert an element, or assign to the current element if the key already exists
(public member function)

emplace

(C++11)

Construct elements in place
(public member functions)

emplace_hint

(C++11)

Use hints to construct elements in situ
(public member functions)

try_emplace

(C++17)

If the key does not exist, insert it in place, if the key exists, do nothing
(public member function)

erase

Erase element
(public member function)

swap

Exchange content
(public member function)

extract

(C++17)

Release the node from another container
(public member function)

merge

(C++17)

从另一容器接合结点
(公开成员函数)

查找

count

返回匹配特定键的元素数量
(公开成员函数)

find

寻找带有特定键的元素
(公开成员函数)

contains

(C++20)

检查容器是否含有带特定键的元素
(公开成员函数)

equal_range

返回匹配特定键的元素范围
(公开成员函数)

lower_bound

返回指向首个不小于给定键的元素的迭代器
(公开成员函数)

upper_bound

返回指向首个大于给定键的元素的迭代器
(公开成员函数)

观察器

key_comp

返回用于比较键的函数
(公开成员函数)

value_comp

返回用于在value_type类型的对象中比较键的函数。
(公开成员函数)

2、std::unordered_map

头文件: <unordered_map>

类声明

template<
    class Key,
    class T,
    class Compare = std::less<Key>,
    class Allocator = std::allocator<std::pair<const Key, T> >
> class map;

namespace pmr { //c++17起
    template <class Key,
              class T,
              class Hash = std::hash<Key>,
              class KeyEqual = std::equal_to<Key>>
              using unordered_map = std::unordered_map<Key, T, Hash, Pred,
                              std::pmr::polymorphic_allocator<std::pair<const Key,T>>>;
}

unordered_map 是关联容器,含有带唯一键的键-值 pair 。搜索、插入和元素移除拥有平均常数时间复杂度。

元素在内部不以任何特定顺序排序,而是组织进桶中。元素放进哪个桶完全依赖于其键的哈希。这允许对单独元素的快速访问,因为一旦计算哈希,则它准确指代元素所放进的桶。

std::unordered_map 满足容器 (Container) 、知分配器容器 (AllocatorAwareContainer) 、无序关联容器 (UnorderedAssociativeContainer) 的要求。

成员函数

(构造函数)

构造 unordered_map
(公开成员函数)

(析构函数)

析构 unordered_map
(公开成员函数)

operator=

赋值给容器
(公开成员函数)

get_allocator

返回相关的分配器
(公开成员函数)

迭代器

begincbegin

返回指向起始的迭代器
(公开成员函数)

endcend

返回指向末尾的迭代器
(公开成员函数)

容量

empty

检查容器是否为空
(公开成员函数)

size

返回容纳的元素数
(公开成员函数)

max_size

返回可容纳的最大元素数
(公开成员函数)

修改器

clear

清除内容
(公开成员函数)

insert

插入元素或结点 (C++17 起)
(公开成员函数)

insert_or_assign

(C++17)

插入元素,或若键已存在则赋值给当前元素
(公开成员函数)

emplace

原位构造元素
(公开成员函数)

emplace_hint

使用提示原位构造元素
(公开成员函数)

try_emplace

(C++17)

若键不存在则原位插入,若键存在则不做任何事
(公开成员函数)

erase

擦除元素
(公开成员函数)

swap

交换内容
(公开成员函数)

extract

(C++17)

从另一容器释出结点
(公开成员函数)

merge

(C++17)

从另一容器接合结点
(公开成员函数)

查找

at

访问指定的元素,同时进行越界检查
(公开成员函数)

operator[]

访问或插入指定的元素
(公开成员函数)

count

返回匹配特定键的元素数量
(公开成员函数)

find

寻找带有特定键的元素
(公开成员函数)

contains

(C++20)

检查容器是否含有带特定键的元素
(公开成员函数)

equal_range

返回匹配特定键的元素范围
(公开成员函数)

桶接口

begin(size_type)

cbegin(size_type)

返回一个迭代器,指向指定的桶的开始
(公开成员函数)

end(size_type)

cend(size_type)

返回一个迭代器,指向指定的桶的末尾
(公开成员函数)

bucket_count

返回桶数
(公开成员函数)

max_bucket_count

返回桶的最大数量
(公开成员函数)

bucket_size

返回在特定的桶中的元素数量
(公开成员函数)

bucket

返回带有特定键的桶
(公开成员函数)

哈希策略

load_factor

返回每个桶的平均元素数量
(公开成员函数)
max_load_factor 管理每个桶的平均元素数量的最大值
(公开成员函数)

rehash

至少为指定数量的桶预留存储空间。
这会重新生成哈希表。
(公开成员函数)

reserve

为至少为指定数量的元素预留存储空间。
这会重新生成哈希表。
(公开成员函数)

观察器

hash_function

返回用于对关键哈希的函数
(公开成员函数)

key_eql

返回用于比较键的相等性的函数
(公开成员函数)
/*================================================================
 *   Copyright (C) 2021 baichao All rights reserved.
 *
 *   文件名称:unordered_map.cpp
 *   创 建 者:baichao
 *   创建日期:2021年01月13日
 *   描    述:
 *
 ================================================================*/

#include <iostream>
#include <string>
#include <unordered_map>

int main()
{
    // 创建三个 string 的 unordered_map (映射到 string )
    std::unordered_map<std::string, std::string> u = {
        {"RED","#FF0000"},
        {"GREEN","#00FF00"},
        {"BLUE","#0000FF"}
    };

    // 迭代并打印 unordered_map 的关键和值
    for( const auto& n : u ) {
        std::cout << "Key:[" << n.first << "] Value:[" << n.second << "]\n";
    }

    // 添加新入口到 unordered_map
    u["BLACK"] = "#000000";
    u["WHITE"] = "#FFFFFF";

    // 用关键输出值
    std::cout << "The HEX of color RED is:[" << u["RED"] << "]\n";
    std::cout << "The HEX of color BLACK is:[" << u["BLACK"] << "]\n";

    //返回哈希函数
    std::hash<std::string> hashFunc = u.hash_function(); //因为unordered_map实例u中的key是std::string类型,所以函数返回值也就是std::hash<std:;string>

    float loadFactor = u.load_factor();
    float maxLoadFactor = u.max_load_factor();

    return 0;
}

 

根据结果可以看到std::unoreded_map的负载因子是1,std::map没有负载因子,负载因子指哈希表中元素和数组大小的比值,std::unoreded_map设置为1,我的理解是为了充分利用内存,但是冲突会比较大。这也是博主稍微有点想不通的原因,难道std::unoreded_map的设计者喜欢反其道而行之,用时间换空间,这个骚操作我也是有点懵逼。

顺带多一嘴,redis的负载因子也是1,redis极端情况下可能是5,就是持久化的时候,需要fork操作,这个时候不会分配内存,所以redis源码中有判断如果大于数组长度的5倍则马上扩容(redis6.0是如此,其余的不敢保证)

 

Guess you like

Origin blog.csdn.net/weixin_40179091/article/details/112503675