c++中unordered_map的用法的详述(包含unordered_map和map的区别)

一、前言

如果要在c++ 中使用这mapunordered_map 两个函数,需要分别引入下面的两个头文件

#include
#include

unordered_map 容器,直译过来就是"无序 map 容器"的意思。所谓“无序”,指的是 unordered_map 容器不会像 map 容器那样对存储的数据进行排序。换句话说,unordered_map 容器和 map 容器仅有一点不同,即 map 容器中存储的数据是有序的,而 unordered_map 容器中是无序的。

二、谈谈unordered_map和map的区别

1、内部实现机理不同

map :map内部实现了一个红黑树(红黑树是非严格平衡二叉搜索树,而AVL是严格平衡二叉搜索树),红黑树具有自动排序的功能,因此map内部的所有元素都是有序的,红黑树的每一个节点都代表着map的一个元素。因此,对于map进行的查找、删除,添加等一系列的操作都相当于是对红黑树进行的操作。map中的元素是按照二叉搜索树 (又名儿茶查找树、二叉排序树–特点就是左子树上所有节点的键值都小于根节点的键值,右子树所有节点的键值都大于根结点的键值)存储的,使用中序遍历可将键值按照从小到大遍历出来。

unordered_map :unordered_map内部实现了一个哈希表 (也叫散列表,通过把关键码值映射到Hash表中一个位置来访问记录,查找的时间复杂度可达到O(1),其在海量数据处理中有着广泛应用)。因此,其元素的排列顺序都是无序的。哈表的概念见:详谈哈希表。

2、谈谈各自的优缺点

  • map

1、优点:

    (1)有序性,这是map结构最大的有点,其元素的有序性在很多应用中都会简化很多的操作。

    (2)红黑树,内部实现一个红黑树使得map的很多操作在lgn的时间复杂度下就可以实现,因此效率非常的高。

2、缺点:空间占用率高,因为map内部实现了红黑树,虽然提高了运行效率,但是因为每一个节点都需要额外保存父节点、孩子节点和红/黑性质,使得每一个节点都占用大量的空间。

3、适用处:对于那些有顺序要求的问题,用map会更高效一些。

  • unordered_map

1、优点:因为内部实现了哈希表,因此其查找速度非常的快。

2、缺点:哈希表的建立比较耗费时间

3、适用处:对于查找问题,unordered_map 会更加高效一些,因此遇到查找问题,常会考虑一下用unordered_map

3、总结

1、内存占有率的问题就转化成红黑树 VS Hash表,还是unorder_map占用的内存要高。

2、但是unorder_map执行效率要比map高很多

3、对于unordered_mapunordered_set 容器,其遍历顺序与创建该容器时输入的顺序不一定相同,因为遍历是按照哈希表从前往后依次遍历的。

三、创建C++ unordered_map容器的方法

(1) 通过调用 unordered_map 模板类的默认构造函数,可以创建空的 unordered_map 容器。比如:

std::unordered_map<std::string, std::string> umap;

由此,就创建好了一个可存储 类型键值对的 unordered_map 容器。

(2) 当然,在创建 unordered_map 容器的同时,可以完成初始化操作。比如:

std::unordered_map<std::string, std::string> umap{
     
    {
     "淘宝","https://www.taobao.com/"},
    {
     "京东","https://www.jd.com/"},
    {
     "天猫商城","https://jx.tmall.com/"} };

(3) 另外,还可以调用 unordered_map 模板中提供的复制(拷贝)构造函数,将现有 unordered_map 容器中存储的键值对,复制给新建 unordered_map 容器。

例如,在第二种方式创建好 umap 容器的基础上,再创建并初始化一个 umap2 容器:

std::unordered_map<std::string, std::string> umap2(umap);

由此,umap2 容器中就包含有 umap 容器中所有的键值对。

除此之外,C++ 11 标准中还向 unordered_map 模板类增加了移动构造函数,即以右值引用的方式将临时 unordered_map 容器中存储的所有键值对,全部复制给新建容器。例如:

//返回临时 unordered_map 容器的函数
std::unordered_map <std::string, std::string > retUmap(){
     
    std::unordered_map<std::string, std::string>tempUmap{
     
        {
     "淘宝","https://www.taobao.com/"},
        {
     "京东","https://www.jd.com/"},
        {
     "天猫商城","https://jx.tmall.com/"} };
    return tempUmap;
}
//调用移动构造函数,创建 umap2 容器
std::unordered_map<std::string, std::string> umap2(retUmap());

注意,无论是调用复制构造函数还是拷贝构造函数,必须保证 2 个容器的类型完全相同。

(4) 当然,如果不想全部拷贝,可以使用 unordered_map 类模板提供的迭代器,在现有 unordered_map 容器中选择部分区域内的键值对,为新建 unordered_map 容器初始化。例如:

//传入 2 个迭代器,
std::unordered_map<std::string, std::string> umap2(++umap.begin(),umap.end());

通过此方式创建的 umap2 容器,其内部就包含 umap 容器中除第 1 个键值对外的所有其它键值对。

四、c++ unordered_map容器的成员方法

下表列出了 unordered_map 类模板提供的所有常用的成员方法、各自的功能和常规的用法。

成员方法 功能 用法
begin() 返回指向容器中第一个键值对的正向迭代器。 a u t o   i t = m y m a p . b e g i n ( ) auto \ it = mymap.begin() auto it=mymap.begin()
end() 返回指向容器中最后一个键值对之后位置的正向迭代器。 i t ! = m y m a p . e n d ( ) it!=mymap.end() it!=mymap.end()
cbegin() 和 begin() 功能相同,只不过在其基础上增加了 const 属性,即该方法返回的迭代器不能用于修改容器内存储的键值对。 a u t o   i t = m y m a p . c b e g i n ( ) auto \ it = mymap.cbegin() auto it=mymap.cbegin()
cend() 和 end() 功能相同,只不过在其基础上,增加了 const 属性,即该方法返回的迭代器不能用于修改容器内存储的键值对。 i t ! = m y m a p . c e n d ( ) it!=mymap.cend() it!=mymap.cend()
empty() 若容器为空,则返回 true;否则 false。 m y m a p . e m p t y ( ) mymap.empty() mymap.empty()
size() 返回当前容器中存有键值对的个数。 m y m a p . s i z e ( ) mymap.size() mymap.size()
max_size() 返回容器所能容纳键值对的最大个数,不同的操作系统,其返回值亦不相同。 m y m a p . m a x _ s i z e ( ) mymap.max\_size() mymap.max_size()
operator[key] 该模板类中重载了 [] 运算符,其功能是可以向访问数组中元素那样,只要给定某个键值对的键 key,就可以获取该键对应的值。注意,如果当前容器中没有以 key 为键的键值对,则其会使用该键向当前容器中插入一个新键值对。 s t r i n g   n a m e = m y m a p [ k e y ] ; m y m a p [ k e y 2 ] = n a m e ; string \ name=mymap[key]; \\ mymap[key2] = name; string name=mymap[key];mymap[key2]=name;
at(key) 返回容器中存储的键 key 对应的值,如果 key 不存在,则会抛出 out_of_range 异常。 m y m a p . a t ( k e y ) = v a l u e ; mymap .at(key) = value; mymap.at(key)=value;
find(key) 查找以 key 为键的键值对,如果找到,则返回一个指向该键值对的正向迭代器;反之,则返回一个指向容器中最后一个键值对之后位置的迭代器(如 end() 方法返回的迭代器)。 m y m a p . f i n d ( k e y ) ; mymap.find(key); mymap.find(key);
count(key) 在容器中查找以 key 键的键值对的个数。 m y m a p . c o u n t ( k e y ) mymap.count(key) mymap.count(key)
equal_range(key) 返回一个 pair 对象,其包含 2 个迭代器,用于表明当前容器中键为 key 的键值对所在的范围。 m y m a p . e q u a l _ r a n g e ( k e y ) ; mymap.equal\_range(key); mymap.equal_range(key);
emplace() 向容器中添加新键值对,效率比 insert() 方法高。 m y m a p . e m p l a c e ( k e y , v a l u e ) ; mymap.emplace(key, value); mymap.emplace(key,value);
emplace_hint() 向容器中添加新键值对,效率比 insert() 方法高。
insert() 向容器中添加新键值对。 m y m a p . i n s e r t ( p a i r < s t r i n g , d o u b l e > ( k e y , v a l u e ) ) ; m y m a p . i n s e r t ( { { k e y , v a l u e } , { k e y , v a l u e } } ) ; mymap.insert(pair(key,value));\\ mymap.insert(\{\{key,value\},\{key,value\}\}); mymap.insert(pair<string,double>(key,value));mymap.insert({ { key,value},{ key,value}});
erase() 删除指定键值对。 m y m a p . e r a s e ( k e y ) ; mymap.erase(key); mymap.erase(key);
clear() 清空容器,即删除容器中存储的所有键值对。 m y m a p . c l e a r ( ) ; mymap.clear(); mymap.clear();
swap() 交换 2 个 unordered_map 容器存储的键值对,前提是必须保证这 2 个容器的类型完全相等。 m y m a p 1. s w a p ( m y m a p 2 ) ; mymap1.swap(mymap2); mymap1.swap(mymap2);
bucket_count() 返回当前容器底层存储键值对时,使用桶(一个线性链表代表一个桶)的数量。 u n s i g n e d   n = m y m a p . b u c k e t _ c o u n t ( ) ; unsigned \ n = mymap.bucket\_count(); unsigned n=mymap.bucket_count();
max_bucket_count() 返回当前系统中,unordered_map 容器底层最多可以使用多少桶。 m y m a p . m a x _ b u c k e t _ c o u n t ( ) mymap.max\_bucket\_count() mymap.max_bucket_count()
bucket_size(n) 返回第 n 个桶中存储键值对的数量。 u n s i g n e d   n b u c k e t s = m y m a p . b u c k e t _ c o u n t ( ) ; unsigned \ nbuckets = mymap.bucket\_count(); unsigned nbuckets=mymap.bucket_count();
bucket(key) 返回以 key 为键的键值对所在桶的编号。 m y m a p . b u c k e t ( k e y ) mymap.bucket (key) mymap.bucket(key)
load_factor() 返回 unordered_map 容器中当前的负载因子。负载因子,指的是的当前容器中存储键值对的数量(size())和使用桶数(bucket_count())的比值,即 load_factor() = size() \ bucket_count()。 m y m a p . l o a d _ f a c t o r ( ) mymap.load\_factor() mymap.load_factor()
max_load_factor() 返回或者设置当前 unordered_map 容器的负载因子。 m y m a p . m a x _ l o a d _ f a c t o r ( ) mymap.max\_load\_factor() mymap.max_load_factor()
rehash(n) 将当前容器底层使用桶的数量设置为 n。 m y m a p . r e h a s h ( 20 ) ; mymap.rehash(20); mymap.rehash(20);
reserve() 将存储桶的数量(也就是 bucket_count() 方法的返回值)设置为至少容纳count个元(不超过最大负载因子)所需的数量,并重新整理容器。 m y m a p . r e s e r v e ( 6 ) ; mymap.reserve(6); mymap.reserve(6);
hash_function() 返回当前容器使用的哈希函数对象。 s t r i n g   m a p : : h a s h e r f n = m y m a p . h a s h _ f u n c t i o n ( ) ; string \ map::hasher fn = mymap.hash\_function(); string map::hasherfn=mymap.hash_function();

注意,对于实现互换 2 个相同类型 unordered_map 容器的键值对,除了可以调用该容器模板类中提供的 swap() 成员方法外,STL 标准库还提供了同名的 swap() 非成员函数。

4、map和unordered_map的使用

unordered_map的用法和map是一样的,提供了insert,size,count等操作,并且里面的元素也是以pair类型来存储的,其底层实现是完全不同的,上方已经解释了,但是就外部使用来说却是一致的。

五、举例说明

#include
#include
#include
#include
using namespace std;

int main()
{
     
    // 注意:c++11才开始支持括号初始化
    unordered_map<int, string> myMap = {
     {
     5, "zhangsan"},{
     6, "lisi"}};  // 使用{}赋值
    myMap[2] = "wanger";  // 使用[ ] 进行当个插入,若已存在键值2,则赋值修改,若无则插之。
    myMap.insert(pair<int, string>(3, "mazi"));  // 使用insert和pair插入。

    // 遍历输出+迭代器的使用。
    auto iter = myMap.begin();  // auto自动识别为迭代器类型unordered_map::iterator
    while(iter != myMap.end())
    {
     
        cout << iter->first << "," << iter->second << endl;
        ++iter;
    }

    // 查找元素并输出 + 迭代器的使用
    auto iterator = myMap.find(6);  // find()返回一个指向2的迭代器。
    if(iterator != myMap.end())
        cout << endl << iterator->first << "," << iterator->second << endl;
    system("pause");
    return 0;
}

此时用unordered_map 的输出结果如下所示:

c++中unordered_map的用法的详述(包含unordered_map和map的区别)_第1张图片

map 的输出结果如下所示:

c++中unordered_map的用法的详述(包含unordered_map和map的区别)_第2张图片

你可能感兴趣的:(C++(+opencv))