• C++ Primer 第十一章 关联容器 重点解读


    1 map自定义排序

    #include 
    #include 
    #include 
    using namespace std;
    int main() {
    	function<bool(pair<int, int>, pair<int, int>)> cmp = [&](pair<int, int> p1, pair<int, int> p2) -> bool {
    		return p1.second < p2.second;
    	};
    	map< pair<int, int>, int, decltype(cmp)> mp({ {{5, 1}, 2}, {{1, 7}, 3}, {{7, 3}, 2}, {{2, 2}, 1} },cmp);
    	//map, int> mp = { {{5, 2}, 2}, {{1, 2}, 3}, {{7, 2}, 2}, {{2, 2}, 1} };
    	for (auto& p : mp) {
    		cout << p.first.first << ' ' << p.first.second << ' ' << p.second << '\n';
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    map的类模板参数
    在这里插入图片描述
    map的构造函数
    在这里插入图片描述

    2 map/unordered_map的下标操作

    2.1 at()

    访问关键字为k的元素,带参数检查:若k不存在容器中,抛出一个out_of_range异常

    2.2 下标运算符与解引用迭代器的区别

    下标运算符:调用insert返回pair用返回的迭代器访问mapped_type

    		V& operator[](const K& key) {
    			pair<iterator, bool> ret = _t.insert(make_pair(key, V()));
    			return ret.first->second;
    		}
    
    • 1
    • 2
    • 3
    • 4

    解引用迭代器返回pair

    2.3 对比vector与map的下标运算符

    map<int, int> m;
    m[0] = 1;
    
    vector<int> v;
    v[0] = 1;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.4 对map使用find替代下标操作

    使用下标操作有一个严重的副作用:如果关键字还未在map中,下标操作会插入一个具有给定关键字的元素(具体原因可以参考2.2节给出的代码),其值为0;

    3 用lower_bound、upper_bound、equal_range查找multimap中的元素

    1. 用lower_bound与upper_bound锁定范围
    //authoers的key为作者,mapped为书名
    //search_item表示要查找的作者
    for (auto beg = authors.lower_bound(search_item), end = authors.upper_bound(search_item); beg != end; ++beg) {
        cout << beg->second << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 用equal_range锁定范围

    equal_range接受一个关键字,返回一个迭代器pair,若关键字存在,则第一个迭代器指向第一个与关键字匹配的元素,第二个迭代器指向最后一个匹配元素之后的位置。若未找到匹配元素,则两个迭代器都指向关键字可以插入的位置

    for (auto pos = authors.equal_range(search_item); pos.first != pos.second; ++pos.first) {
        cout << pos.first.second << endl;   
    }
    
    • 1
    • 2
    • 3

    4 将自定义类型作为无序容器的关键字

    默认情况下,无序容器使用关键字类型的==运算符来比较元素,他们还使用一个hash类型的对象(仿函数)来生成每个元素的哈希值。标准库为内置类型(包括指针)提供了hash模板,还为一些标准库类型,比如string和智能指针类型定义了hash。

    那么如何定义关键字为自定义类型的无序容器呢?

    4.1类模板特化

    namespace std {
        template<>
        struct hash<Sales_data> {
            //用来散列一个无需容器的类型必须要定义下列类型
            typedef size_t result_type;
            typedef Sales_data argument_type;    //默认情况下,此类型需要operator==
            size_t operator()(const Sales_data& s) const {
                return hash<string>() (s.bookNo) ^      //构造匿名对象调用operator()返回一个哈希值
                       hash<unsigned>() (s.units_sold) ^ 
                       hash<double>() (s.revenue);
            }
        }
    }  //关闭std命名空间
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4.2 通过类模板传参

    size_t hasher(const Sales_data& sd) {
        return hash<string>() (sd.isbn());
    }
    //如果类中定义了operator==则只需重载哈希函数
    bool eqOp(const Sales_data& lhs, const Sales_data& rhs) {    
        return lhs.isbn() == rhs.isbn();
    }
    int main() {
    	using SD_multiset = unordered_multiset<Sales_data, decltype(hahser)*, decltype(eqOp)*>;   //C++11
        
        //参数是桶大小、哈希函数指针和相等性判断运算符指针
        SD_multiset bookstore(42, hasher, eqOp);   
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 为什么能通过上述代码完成自定义类型作为无序容器的关键字呢?
    1. 模板参数

    在这里插入图片描述

    以下是unordered_multiset类的成员类型,其中key_equal是typedef的第三个模板参数,该类创建的对象用于调用operator==比较两关键字是否相等。

    member typedefinitionnotes
    key_typethe first template parameter (Key)
    mapped_typethe second template parameter (T)
    value_typepair
    hasherthe third template parameter (Hash)defaults to: hash
    key_equalthe fourth template parameter (Pred)defaults to: equal_to
    allocator_typethe fifth template parameter (Alloc)defaults to: allocator
    referenceAlloc::reference
    const_referenceAlloc::const_reference
    pointerAlloc::pointerfor the default allocator: value_type*
    const_pointerAlloc::const_pointerfor the default allocator: const value_type*
    iteratora forward iterator to value_type
    const_iteratora forward iterator to const value_type
    local_iteratora forward iterator to value_type
    const_local_iteratora forward iterator to const value_type
    size_typean unsigned integral typeusually the same as size_t
    difference_typea signed integral typeusually the same as ptrdiff_t
    1. equal_to类模板的实现:

    在这里插入图片描述

    equal_to类在容器中创建的对象:key_eq(其他无序容器均有)
    在这里插入图片描述
    在这里插入图片描述

    1. 对于unordered系列的构造函数,都有一个接受unsigned int参数的构造函数,表示哈希桶的大小,且不能被隐式类型转换
      在这里插入图片描述

    5 无序容器的管理操作

    • Buckets
      • bucket_count

        Return number of buckets (public member function)

      • max_bucket_count

        Return maximum number of buckets (public member function)

      • bucket_size

        Return bucket size (public member type)

      • bucket

        Locate element’s bucket (public member function)

      Hash policy
      • load_factor

        Return load factor (public member function)

      • max_load_factor

        Get or set maximum load factor (public member function )

      • rehash

        Set number of buckets (public member function )

      • reserve

        Request a capacity change (public member function)

    #include 
    #include 
    using namespace std;
    int main() {
    	unordered_map<int, int> mp(8);
    	cout << mp.bucket_count() << endl;    //output: 8
    	mp.insert({ 1, 1 });
    	mp.insert({ 2, 1 });
    	mp.insert({ 3, 1 });
    	mp.insert({ 11, 1 });
    	for (int i = 0; i < 8; i++) {
    		cout << mp.bucket_size(i) << ' ';     //output:0 0 0 0 1 0 2 1
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    6 总结

    • 有序容器(set multiset map multimap)底层为红黑树,使用比较函数来比较关键字,从而将元素按顺序存储。默认情况下,比较操作是采用关键字类型的**<运算符(operator <)**

    • 无序容器(unordered_set unordered_multiset unordered_map unordered_multimap)底层是哈希桶,使用关键字类型的**==运算符(operator ==)和一个hash类型的对象来计算哈希值从而组织对象(放入哪个哈希桶中)
      ,使用比较函数来比较关键字,从而将元素按顺序存储。默认情况下,比较操作是采用关键字类型的
      <运算符(operator <)
      *

    • 无序容器(unordered_set unordered_multiset unordered_map unordered_multimap)底层是哈希桶,使用关键字类型的**==运算符(operator ==)**和一个hash类型的对象来计算哈希值从而组织对象(放入哪个哈希桶中)

  • 相关阅读:
    CSS复习笔记
    ORM数据库操作
    【高德地图API】JS高德地图API实现多边形绘画,高德获取多边形提交数据
    pytorch代码实现之动态卷积模块ODConv
    【电磁】基于Matlab实现理想圆柱形电流片的精确磁场
    2023常州大学计算机考研信息汇总
    ARP欺骗攻击
    Codeforces Round #832 (Div. 2)「D 思维 + 异或前缀和 + 奇偶二分优化」
    计算机中实数的比较
    西北主要河流水系(绿洲)流域(山区)及高程分类数据集(一)
  • 原文地址:https://blog.csdn.net/Dusong_/article/details/133937177