关联容器
关联容器中的元素是按关键字来保存和访问的。 而顺序容器中的元素是按他们在容器中的位置来顺序保存和访问的。
类型
- 按关键字有序保存:
- 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占用最高