• C++笔记 —— map常用方法


    map的底层实现是红黑树,map是有序的,增删查改一个元素的时间复杂度都是O(log n),使用迭代器遍历map的时间复杂度是O(n)

    map的标准定义如下:

     1 template < class Key,                                     // map::key_type
     2            class T,                                       // map::mapped_type
     3            class Compare = less<Key>,                     // map::key_compare
     4            class Alloc = allocator<pair<const Key,T> >    // map::allocator_type
     5            > class map;
    

    map中的的键和值都可以使用用户自定义的数据类型,键的比较也可以被自定义。

    自定义举例如下,按Mykey中的key值的绝对值从大到小排序,如果key是基本数据类型且不需要特殊排序方式,则不用自定义排序方式。

     1 typedef struct Key{
     2     int key;
     3 } MyKey;
     4 
     5 typedef struct Value{
     6     string value;
     7 } MyValue;
     8 
     9 typedef struct Comp{
    10     bool operator()(const MyKey & k1, const MyKey & k2){
    11         return abs(k1.key) > abs(k2.key);
    12     }
    13 } MyComp;
    14 
    15 typedef map<MyKey, MyValue, MyComp> MyMap;

     声明一个map常用方法有以下四种,声明空map,枚举元素(可以用makepair代替),复制构造函数,利用迭代器实现部分复制

    1 map<int, string> a; // 声明空map
    2 map<int, string> b{{1, "aaa"}, {2, "bbb"}}; // 枚举初始化元素
    3 map<int, string> c(b); // 复制构造函数
    4 map<int, string> d(begin(b),end(b)); // 通过迭代器实现按区间复制

    map中键是唯一的,以上声明方式中的第二种,如果出现重复的key,后出现的不会覆盖前出现的,而是会以前出现的为准。如下所示

    1 map<int, string> e{{1, "aaa"}, {1, "bbb"}};
    2 cout << e.size() << endl; // 1
    3 cout << e.find(1)->second; // "aaa"

     插入。前三者是等价的,利用前三种方法插入一个键值对,如果插入的键已存在,编译器会报错,而第四种写法会直接覆盖原先的键值对。

    1 a.insert(pair<int, string>(1,"aaa"));
    2 a.insert(make_pair<int, string>(2,"bbb"));
    3 a.insert(map<int, string>::value_type(3,"ccc"));
    4 a[4] = "ddd";

    查找。注意,在使用[]运算符返回map中的一个键对应的值时,需要先判断值该键值对是否存在。当使用[]时即使查找的键不存在编译器也不会报错,而是返回垃圾值。

    通常可以使用count和find方法判断一个键是否存在,由于map内部时有序的所以不需要遍历全部键值对。count返回个数,find返回找到的元素的位置,如果找不到返回map的末尾位置。以下展示了两种方法寻找键值对,第二种方法更好,因为第一种方法找了两遍。[]运算符可以使用at成员函数代替。

    1 if(a.count(2) > 0) // 方法一
    2     return a[2];
    3 
    4 auto iter1 = a.find(2);// 方法二
    5 if(iter != end(a))
    6     return iter->second;

    修改。可以使用直接赋值修改或者使用迭代器修改。前者需要先判断是否存在在修改,后者不需要。另外,map的迭代器支持++运算但是不支持+i运算,只能根据键修改值,而不能修改键(必须要删除后重新插入)

    1 a[4] = "ddd"; // 方法一
    2 
    3 auto iter2 = ++a.begin(); // 方法二
    4 iter2->second = "eee";

    删除,修改一个元素到红黑树的时间复杂度O(log N)

    1 a.erase(1); // 删除指定键值的元素
    2 a.erase(a.begin()); // 删除迭代器指向的元素
    3 a.erase(a.begin(), a.end()); // 删除迭代器区间内的元素
    4 a.clear(); // 清空所有元素

    使用迭代器遍历红黑树时间复杂度O(N)

    方法一,使用传统的迭代器遍历,map的迭代器属于双向迭代器,只支持向前加一或者向后减一的操作。

    方法二,如果要遍历整个map而不是某一部分,可以使用C++11中引入的按范围的for循环。按范围的for循环中的it迭代器本质上是映射f的右值引用。因此利用it取键值要用 . 运算符而不是 ->

    1 map<int, string> f{{1,"a"}, {2,"b"}, {3,"c"}};
    2 
    3 for(auto iter = f.begin(); iter != f.end(); ++iter)
    4     cout << iter->first << " : " << iter->second << endl; // 方法一
    5 
    6 for(auto it : f)
    7     cout << it.first << " : " << it.second << endl; // 方法二

    其他操作

    size():返回map的大小

    empty():返回一个bool值判断map是否为空

    swap(map1, map2):无返回值,swap是用来交换两个map的内容而不是用来交换map中的内容。

    equal_range(iter1, iter2, val):以pair的形式返回一对迭代器,返回得迭代器的范围等于iter1和iter2中值等于val的范围

    lower_bound(key):返回map中第一个大于等于key的迭代指针

    upper_bound(key):返回map中第一个大于key的迭代指针

    emplace(key, val):生成一个pair(key,val),并且把这个pair插入到map中,返回值是一个pair,其中first是一个迭代器,second是一个bool类型。当插入成功,迭代器指向新插入的元素,bool为true,当插入失败,迭代器指向map中原来已有的key和要插入的key相同的键值对,bool位false。

    emplace_hint(iter, key, val):作用和emplace相同,不过插入位置由iter指定,而且返回值是迭代器(就是上面的那个first)。对于插入一个元素,使用emplace和emlace_hint效率比insert更高.

    key_comp():返回一个用于比较key的比较器

    value_comp():返回一个用于比较value的比较器

    特殊的迭代器

    begin,end,cbegin,cend,rbegin,rend,crbegin,crend

  • 相关阅读:
    GNU C的定义长度为0的数组
    Ubuntu如何启用双网卡
    DQN 文章第一篇
    awk用法
    Linux下C结构体初始化
    Linux kernel中的list怎么使用
    从美剧中学(1)
    Python @property 属性
    p40_数据交换方式
    3.TCP协议
  • 原文地址:https://www.cnblogs.com/LC32/p/13114726.html
Copyright © 2020-2023  润新知