zoukankan      html  css  js  c++  java
  • map/unordered_map

    1. map

       1)map是标准的关联式容器,一个map是一个键值对序列,即(key,value)对。它提供基于key的快速检索能力。

       2)map中key值是唯一的。集合中的元素按一定的顺序排列。元素插入过程是按排序规则插入,所以不能指定插入位置。

       3)map的具体实现采用红黑树变体的平衡二叉树的数据结构。在插入操作和删除操作上比vector快。

       4)map可以直接存取key所对应的value,支持[]操作符,如map[key]=value。

       map对象的构造

    map<T1,T2> mapX;

       map的插入与迭代器

    map<int, string> mapStu;
    mapStu.insert(pair<int,string>(3,"Jack"));            // return pair<map<int, string>::iterator,bool>
    mapStu.inset(make_pair(0, "John"));                   // return pair<map<int, string>::iterator,bool>
    mapStu.insert(map<int,string>::value_type(1,"小李")); // return pair<map<int, string>::iterator,bool>
    void insert(InputIterator first, InputIterator last); // 插入一个范围
    
    mapStu[3] = "小明";          // 这种方法虽然非常直观,但存在一个性能的问题。插入3时,先在mapStu中查找主键为3的项,
                                 // 若没发现,则将一个键为3,值为初始化值的对组插入到mapStu中,然后再将值修改成"小明"。
                                 // 若发现已存在3这个键,则修改这个键对应的value
    string strName = mapStu[2];  // 只有当mapStu存在2这个键时才是正确的取操作,否则会自动插入一个实例,键为2,值为初始化值。
     
    map.begin();   // 返回容器中第一个数据的迭代器。
    map.end();     // 返回容器中最后一个数据之后的迭代器。
    map.rbegin();  // 返回容器中倒数第一个元素的迭代器。
    map.rend();    // 返回容器中倒数最后一个元素的后面的迭代器。
     
    // 迭代器遍历
    for (map<int,string>::iterator it=mapA.begin(); it!=mapA.end(); ++it)
    {
        pair<int, string> pr = *it;
        int iKey = pr.first;
        string sValue = pr.second;
    }

       map选择key排序方式

    map<T1,T2,less<T1> >  mapA;    // 该容器是按键的升序方式排列元素。未指定函数对象,默认采用less<T1>函数对象。
    map<T1,T2,greater<T1>> mapB;   // 该容器是按键的降序方式排列元素。
    // less<T1> 与 greater<T1> 可以替换成其它的函数对象functor。
    

       map对象的拷贝构造与赋值

    map(const map &mp);             // 拷贝构造函数
    map& operator=(const map &mp);  // 重载等号操作符
    map.swap(mp);                   // 交换两个容器集合
    

       map的大小

    map.size();   // 返回容器中元素的数目
    map.empty();  // 判断容器是否为空
    

       map的删除

    map.clear();                                                  // 删除所有元素
    iterator  erase(const_iterator position);                     // 删除pos迭代器所指的元素,返回下一个元素的迭代器
    size_type erase(const key_type& k);                           // 删除容器中key为k的pair
    iterator  erase(const_iterator first, const_iterator last);   // 除区间[beg,end)的所有元素,返回下一个元素的迭代器
    

       map的查找

    iterator find(const key_type& k);          // 查找键key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回map.end();
    size_type count(const key_type& k) const;  // 返回容器中key为 k 的对组个数。对map来说,要么是0,要么是1
    iterator lower_bound(const key_type& k);   // 返回第一个 key>=k 元素的迭代器
    iterator upper_bound(const key_type& k);   // 返回第一个 key>k 元素的迭代器
    

    2. unordered_map

       它是一个关联容器,内部采用的是hash表结构,拥有快速检索的功能。每个key会通过一些特定的哈希运算映射到一个特定的位置,我们知道,

       hashtable是可能存在冲突的(多个key通过计算映射到同一个位置),在同一个位置的元素会按顺序链在后面。所以把这个位置称为一个bucket是

       十分形象的(像桶子一样,可以装多个元素)。

       

       所以 unordered_map 内部其实是由很多哈希桶组成的,每个哈希桶中可能没有元素,也可能有多个元素。每当桶不够用时,桶数会以

       大致 bucket[n] = 2 * bucket[n-1] + 奇数 (1, 3, 5, 9 ...)来增长。与 vector 成倍增长是不同的。

       这里我们将map和unordered_map做一个对比:

       1)map在缺省下,按照递增的排序顺序unordered_map不排序。

       2)Map中桶的元素初始化是链表保存的,其查找性能是O(n)。当链表长度很小的时候,即使遍历,速度也非常快,但是当链表长度不断

          变长,肯定会对查询性能有一定的影响,而树结构能将查找性能提升到O(log(n)),这时map内部存储结构由链表转成树。

          unordered_map内部实现是哈希表(数组),由链地址法解决冲突。

       3)map搜索时间复杂度为log(n)。unordered_map搜索时间复杂度,O(1)为平均时间,最坏情况下的时间复杂度为O(n)。

       4)map空间占用率高,因为map内部实现了红黑树,虽然提高了运行效率,但是因为每一个节点都需要额外保存父节点,孩子节点以及红/黑性质,

          使得每一个节点都占用大量的空间。unordered_map建立哈希表比较耗费时间,但查找速度更快(受到冲突的影响)。

       unordered_map对象的构造

    unordered_map<T1,T2> mapX;
    

       unordered_map的插入与迭代器

    std::unordered_map<std::string, double> map1, map2 = { {"milk",2.0},{"flour",1.5} };
    std::pair<std::string, double> myshopping("baking powder",0.3);
    
    map1.insert(myshopping);                                      // copy insertion
    map1.insert(std::make_pair<std::string, double>("eggs",6.0)); // move insertion
    map1.insert(map2.begin(), map2.end());                        // range insertion
    map1.insert({ {"sugar",0.8}, {"salt",0.1} });                 // initializer list insertion
    
    umap.begin();   // 返回容器中第一个数据的迭代器。
    umap.end();     // 返回容器中最后一个数据之后的迭代器。
    
    for (auto& x: map1) {
        std::cout << x.first << ": " << x.second << std::endl;
    }
    

       自定义哈希函数

       使用自定义哈希函数可以有效避免构造数据产生的大量哈希冲突。要想使用自定义哈希函数,需要定义一个结构体,并在结构体中重载()运算符。

    // 通过 unordered_map<int, int, my_hash> my_map; 的定义方式将自定义的哈希函数传入容器了。
    struct my_hash 
    {
        static uint64_t splitmix64(uint64_t x) 
        {
            x += 0x9e3779b97f4a7c15;
            x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
            x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
            return x ^ (x >> 31);
        }
    
        size_t operator()(uint64_t x) const 
        {
            static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
            return splitmix64(x + FIXED_RANDOM);
        }
    };
    

       unordered_map对象的拷贝构造与赋值

    unordered_map(const unordered_map& ump);             // 拷贝构造函数
    unordered_map(unordered_map&& ump);                  // 移动构造函数
    unordered_map& operator=(const unordered_map& ump);  // 重载赋值运算符
    unordered_map& operator=(unordered_map&& ump);       // 移动赋值
    void swap(unordered_map& ump);                       // 交换两个容器集合
    

       unordered_map的大小

    umap.size();          // 返回容器中元素的数目
    umap.empty();         // 判断容器是否为空
    umap.bucket_count();  // 返回容器中桶的数目
    umap.bucket_size(n);  // 返回第n个桶中元素个数 
    

       unordered_map的删除

    umap.clear();                                                 // 删除所有元素
    iterator  erase(const_iterator position);                     // 删除pos迭代器所指的元素,返回下一个元素的迭代器
    size_type erase(const key_type& k);                           // 删除容器中key为k的pair
    iterator  erase(const_iterator first, const_iterator last);   // 除区间[beg,end)的所有元素,返回下一个元素的迭代器
    

       unordered_map的查找

    iterator find(const key_type& k);          // 查找键key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回umap.end();
    size_type count(const key_type& k) const;  // 返回容器中key为 k 的对组个数。对umap来说,要么是0,要么是1
    

      

  • 相关阅读:
    Data Base mysql备份与恢复
    java 乱码问题解决方案
    【知识强化】第二章 物理层 2.1 通信基础
    【知识强化】第二章 进程管理 2.2 处理机调度
    【知识强化】第二章 进程管理 2.1 进程与线程
    【知识强化】第一章 操作系统概述 1.3 操作系统的运行环境
    【知识强化】第一章 网络体系结构 1.1 数据结构的基本概念
    【知识强化】第一章 网络体系结构 1.2 计算机网络体系结构与参考模型
    【知识强化】第一章 网络体系结构 1.1 计算机网络概述
    【知识强化】第一章 操作系统概述 1.1 操作系统的基本概念
  • 原文地址:https://www.cnblogs.com/yanghh/p/13036091.html
Copyright © 2011-2022 走看看