第十一章、关联容器

关联容器

关联容器中的元素是按关键字来保存和访问的。 而顺序容器中的元素是按他们在容器中的位置来顺序保存和访问的。

类型

  • 按关键字有序保存:
    • map: 元素是 关键字-值
    • 和multimap(关键字可重复出现)一起定义在头文件map中
    • set : 元素只有 关键字
    • 和multiset定义在头文件set中
    • set的底层是红黑树
  • 无序集合
    • unordered_map
    • unordered_set
    • unordered_multimap
    • unordered_multiset
    • 定义在头文件unordered_map和unordered_set中。
  • 类型别名
    • key_type : 关键字类型。
    • set<string>::key_type v1;
    • v1是一个string
    • mapped_type : 关联的类型(只适用于map)
    • map<string,int>::mapped_type v2;
    • v2是一个int
    • value_type:
    • 对于set ,与key_type一样;对于map, 是一个pair类型。
    • map<string,int>::value_type v3;
    • v3是一个 pair<conststring,int>
      • 对于pair类型,关键字不应该被改变。所以应是 const

用法

  • 迭代器

    • set的迭代器是const的。
  • 通常不对关联容器使用泛型算法。

    • 关键字是const 意味着不能对关联容器使用修改或者重排容器元素的算法。

    • 有一个专用的find算法成员 (因为关联容器不能通过关键字进行查找 ? .)

insert函数

  • 对于map和set,对其插入一个已存在的元素对容器没有任何影响。
  • 对于map容器,返回值是一个pair类型。*first成员是一个迭代器,指向具有给定关键字的元素*。 second成员是一个bool类型,如果要插入的关键字已经存在,则值为0并且插入操作什么都不做,否则是1。
    • 所以要先取出返回值的first成员,然后对其解引用,再取出解引用后的second成员 就是要插入的那个关键字映射(关联)的值。
  • 对于map 新特性写法: word_cout.insert({word,1});
    • 创建一个pair最简单的方法就是在参数列表使用花括号初始化。
    • 当然也可以调用make_pair 或者显示的初始化。

erase函数

  • c.erase(key_type)
    • 删除C中每个给定关键字的元素(可以给出多个关键字)
    • 返回一个size_type值,表示删除的元素的数量。
  • c.erase(iter)
    • 删除迭代器指定的元素。(注意迭代器不能指向c.end() ,越界)
    • 返回一个指向P之后一个元素的迭代器。
  • c.erase(iter_1, iter_2)
    • 删除两个迭代器范围内的元素 ,[b,e) ← 左闭合区间
    • 返回值是 iter_2

下标操作

  • set不支持下标操作
  • map的下标操作,下标就是关键字
    • 不能对unordered_multimap或者multimap执行下标操作,因为返回值不一定唯一。
    • 如果关键字不在map中,会自动创建一个元素插入到map,并对mapped_type 进行值初始化
  • 下标操作和at操作 仅适用于非const的map和unordered_map。

下标操作和insert的区别

  • 如果map中没有给定关键字,insert和下标操作+赋值效果类似

  • 如果map中给出了关键字

    • 下标操作会获得具有该关键字的元素,并且将新的值赋给它

    • insert在这种情况,不会改变容器内容,而是返回一个值,表示插入失败。

查找操作

  • find :
    • c.find(k) : 返回一个迭代器,指向第一个关键字为K的元素。 若没有K 则返回尾后迭代器。
  • count :
    • c.count(k) : 返回关键字等于K的元素的个数。
  • lower_bound & upper_bound & equal_range
    • c.lower_bound(k) : 返回迭代器,指向第一个关键字不小于k的元素。(返回第一个等于k的元素) 。
    • 如果没有K则返回K的安全插入点(第一个关键字大于K的元素,在它之前插入是安全的)。
    • upper 返回第一个大于k的元素。
    • (返回等于k的元素后的第一个元素)。 如果没有K,则返回和lower_bound一样
    • c.equal_range(k); : 返回一个pair , first和second都是迭代器。表示关键字等于k的元素的范围。 若没有则两个都是c.end();
    • equal_range 相当于同时调用了 lower_bound和upper_bound. 返回两个迭代器,组成一个pair类型。

特点

  • 关联容器不支持顺序容器的位置相关操作,也不支持构造函数或者插入操作。
  • 它的迭代器都是双向的。

pair类型

  • 定义在头文件 utility
  • 三种创建pair的方法.
    • pair< T1,T2 > p(v1,v2);
    • pair< T1,T2 > p={v1,v2};
    • make_pair(v1,v2)
    • v1 v2的类型从T1,T2推断出来

无序容器

  • 无序版本通常性能更好,使用更简单。

    • 当关键字类型没有明显的序关系时,或者维护元素的序代价很高时,选择使用无序容器。
  • 有序版本的优势是维护了关键词的序。

    • 要求必须维护元素的序时,选择有序版本。

哈希map (unordered_ map)和map的区别:

一、unordered_map

哈希map是一种关联容器,通过键值和映射值存储元素。允许根据键值快速检索各个元素。
在unordered_map中,键值一般用来唯一标识元素,而对应的值是一个对象关联到这个键的内容。键映射值的类型可能会有所不同。
在内部unordered_map的元素不以键值或映射的元素作任何特定的顺序排序,其存储位置取决于哈希值,允许直接通过其键值为快速访问单个元素(具有恒定平均的平均时间复杂度)。
unordered_map容器比map容器更快地通过键值访问他们的单个元素,虽然unordered_map一般都是比map通过其元素的一个子集范围迭代效率低。
哈希map允许使用操作运算符(运算符[])以其键值作为参数直接访问元素。

二、unordered_map与map的区别

boost::unordered_map, 它与 stl::map的区别就是,stl::map是按照operator<比较判断元素是否相同,以及比较元素的大小,然后选择合适的位置插入到树中。所以,如果对map进行遍历(中序遍历)的话,输出的结果是有序的。顺序就是按照operator< 定义的大小排序。
boost::unordered_map是计算元素的Hash值,根据Hash值判断元素是否相同。所以,对unordered_map进行遍历,结果是无序的。
用法的区别就是,stl::map 的key需要定义operator< 。 而boost::unordered_map需要定义hash_value函数并且重载operator==。对于内置类型,如string,这些都不用操心。对于自定义的类型做key,就需要自己重载operator== 或者hash_value()了。
当不需要结果排好序时,最好用unordered_map。
stl::map对于与java中的TreeMap,而boost::unordered_map对应于java中的HashMap。

三、map hash_map和unordered_map效率比较

运行效率方面:unordered_map最高,hash_map其次,而map效率最低

占用内存方面:hash_map内存占用最低,unordered_map其次,而map占用最高

发布了29 篇原创文章 · 获赞 3 · 访问量 7139

猜你喜欢

转载自blog.csdn.net/liu432linux/article/details/79241323