目录
一、关联容器概述
关联容器支持高效的关键字查找和访问。两个主要的关联容器类型是 map 和 set。map中的元素是一些关键字-值(key-value)对:关键字起到索引的作用,值则表示与索引相关联的数据。set 中每个元素只包含一个关键字。
标准库提供8个关联容器,这8个关联容器间的不同体现在三个维度上:每个容器(1)或者是一个 set,或者是一个 map;(2)或者要求不重复的关键字,或者允许重复的关键字;(3)按顺序保存元素,或无序保存。允许重复关键字的容器的名字中都包含单词 multi;不保持关键字按顺序存储的容器的名字都以单词 unordered 开头。
有序关联容器基于一个序标准(默认是小于比较操作<)进行查找。这类容器用平衡二叉树实现,通常是红黑树(有关红黑树的内容请参看 STL之红黑树)。
无序关联容器基于一个哈希函数进行查找。这类容器用哈希表实现,采用溢出链表策略(有关哈希表的内容请参看STL之哈希表)。
二、关联容器
2.1、set
set 的特性是,所有元素都会根据元素的键值自动被排序。由于 set 元素值就是其键值,关系到 set 元素的排列规则,因此不可以通过 set 的迭代器改变 set 的值。
标准库的 set 以 RB-tree 为底层机制,set 操作通过调用 RB-tree 的接口实现:
template <typename _Key, typename _Compare = std::less<_Key>,
typename _Alloc = std::allocator<_Key>>
class set
{
typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Key>::other _Key_alloc_type;
typedef _Rb_tree<key_type, value_type, _Identity<value_type>,
key_compare, _Key_alloc_type> _Rep_type;
_Rep_type _M_t; // Red-black tree representing set.
std::pair<iterator, bool>
insert(value_type &&__x)
{
std::pair<typename _Rep_type::iterator, bool> __p =
_M_t._M_insert_unique(std::move(__x));
return std::pair<iterator, bool>(__p.first, __p.second);
}
...
};
2.2、multiset
multiset 的特性以及用法和 set 完全相同,唯一的差别在于它允许键值重复,因此它的插入操作采用的是底层机制 RB-tree 的 _M_insert_equal() 而非 _M_insert_unique()。
template <typename _Key, typename _Compare = std::less<_Key>,
typename _Alloc = std::allocator<_Key>>
class multiset
{
/// This turns a red-black tree into a [multi]set.
typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Key>::other _Key_alloc_type;
typedef _Rb_tree<key_type, value_type, _Identity<value_type>,
key_compare, _Key_alloc_type> _Rep_type;
/// The actual tree structure.
_Rep_type _M_t;
iterator
insert(value_type &&__x)
{
return _M_t._M_insert_equal(std::move(__x));
}
...
};
2.3、map
map 的特性是,所有元素都会根据元素的键值自动被排序。map 的所有元素都是 pair,同时拥有实值和键值。
标准库的 map 以 RB-tree 为底层机制,map 操作通过调用 RB-tree 的接口实现:
template <typename _Key, typename _Tp, typename _Compare = std::less<_Key>,
typename _Alloc = std::allocator<std::pair<const _Key, _Tp>>>
class map
{
/// This turns a red-black tree into a [multi]map.
typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<value_type>::other _Pair_alloc_type;
typedef _Rb_tree<key_type, value_type, _Select1st<value_type>,
key_compare, _Pair_alloc_type> _Rep_type;
/// The actual tree structure.
_Rep_type _M_t;
std::pair<iterator, bool>
insert(value_type &&__x)
{
return _M_t._M_insert_unique(std::move(__x));
}
...
};
2.4、multimap
multimap的特性以及用法和 map 完全相同,唯一的差别在于它允许键值重复,因此它的插入操作采用的是底层机制 RB-tree 的 _M_insert_equal() 而非 _M_insert_unique()。
template <typename _Key, typename _Tp,
typename _Compare = std::less<_Key>,
typename _Alloc = std::allocator<std::pair<const _Key, _Tp>>>
class multimap
{
/// This turns a red-black tree into a [multi]map.
typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<value_type>::other _Pair_alloc_type;
typedef _Rb_tree<key_type, value_type, _Select1st<value_type>,
key_compare, _Pair_alloc_type> _Rep_type;
/// The actual tree structure.
_Rep_type _M_t;
iterator
insert(value_type &&__x)
{
return _M_t._M_insert_equal(std::move(__x));
}
...
};
2.5、unordered_set
unordered_set以哈希表为底层机制,unordered_set操作通过调用哈希表的接口实现:
/// Base types for unordered_set.
template <bool _Cache>
using __uset_traits = __detail::_Hashtable_traits<_Cache, true, true>;
template <typename _Value,
typename _Hash = hash<_Value>,
typename _Pred = std::equal_to<_Value>,
typename _Alloc = std::allocator<_Value>,
typename _Tr = __uset_traits<__cache_default<_Value, _Hash>::value>>
using __uset_hashtable = _Hashtable<_Value, _Value, _Alloc,
__detail::_Identity, _Pred, _Hash,
__detail::_Mod_range_hashing,
__detail::_Default_ranged_hash,
__detail::_Prime_rehash_policy, _Tr>;
template <typename _Value,
typename _Hash = hash<_Value>,
typename _Pred = equal_to<_Value>,
typename _Alloc = allocator<_Value>>
class unordered_set
{
typedef __uset_hashtable<_Value, _Hash, _Pred, _Alloc> _Hashtable;
_Hashtable _M_h;
std::pair<iterator, bool>
insert(value_type &&__x)
{
return _M_h.insert(std::move(__x));
}
...
};
2.6、unordered_multiset
unordered_multiset的特性以及用法和 unordered_set完全相同,唯一的差别在于它允许键值重复。
/// Base types for unordered_multiset.
template <bool _Cache>
using __umset_traits = __detail::_Hashtable_traits<_Cache, true, false>;
template <typename _Value,
typename _Hash = hash<_Value>,
typename _Pred = std::equal_to<_Value>,
typename _Alloc = std::allocator<_Value>,
typename _Tr = __umset_traits<__cache_default<_Value, _Hash>::value>>
using __umset_hashtable = _Hashtable<_Value, _Value, _Alloc,
__detail::_Identity,
_Pred, _Hash,
__detail::_Mod_range_hashing,
__detail::_Default_ranged_hash,
__detail::_Prime_rehash_policy, _Tr>;
template <typename _Value,
typename _Hash = hash<_Value>,
typename _Pred = equal_to<_Value>,
typename _Alloc = allocator<_Value>>
class unordered_multiset
{
typedef __umset_hashtable<_Value, _Hash, _Pred, _Alloc> _Hashtable;
_Hashtable _M_h;
iterator
insert(value_type &&__x)
{
return _M_h.insert(std::move(__x));
}
...
};
2.7、unordered_map
unordered_map以哈希表为底层机制,unordered_map操作通过调用哈希表的接口实现:
/// Base types for unordered_map.
template <bool _Cache>
using __umap_traits = __detail::_Hashtable_traits<_Cache, false, true>;
template <typename _Key,
typename _Tp,
typename _Hash = hash<_Key>,
typename _Pred = std::equal_to<_Key>,
typename _Alloc = std::allocator<std::pair<const _Key, _Tp>>,
typename _Tr = __umap_traits<__cache_default<_Key, _Hash>::value>>
using __umap_hashtable = _Hashtable<_Key, std::pair<const _Key, _Tp>,
_Alloc, __detail::_Select1st,
_Pred, _Hash,
__detail::_Mod_range_hashing,
__detail::_Default_ranged_hash,
__detail::_Prime_rehash_policy, _Tr>;
template <typename _Key, typename _Tp,
typename _Hash = hash<_Key>,
typename _Pred = equal_to<_Key>,
typename _Alloc = allocator<std::pair<const _Key, _Tp>>>
class unordered_map
{
typedef __umap_hashtable<_Key, _Tp, _Hash, _Pred, _Alloc> _Hashtable;
_Hashtable _M_h;
template <typename _Pair>
__enable_if_t<is_constructible<value_type, _Pair &&>::value,
pair<iterator, bool>>
insert(_Pair &&__x)
{
return _M_h.emplace(std::forward<_Pair>(__x));
}
...
};
2.8、unordered_multimap
unordered_multimap的特性以及用法和 unordered_map完全相同,唯一的差别在于它允许键值重复。
/// Base types for unordered_multimap.
template <bool _Cache>
using __ummap_traits = __detail::_Hashtable_traits<_Cache, false, false>;
template <typename _Key,
typename _Tp,
typename _Hash = hash<_Key>,
typename _Pred = std::equal_to<_Key>,
typename _Alloc = std::allocator<std::pair<const _Key, _Tp>>,
typename _Tr = __ummap_traits<__cache_default<_Key, _Hash>::value>>
using __ummap_hashtable = _Hashtable<_Key, std::pair<const _Key, _Tp>,
_Alloc, __detail::_Select1st,
_Pred, _Hash,
__detail::_Mod_range_hashing,
__detail::_Default_ranged_hash,
__detail::_Prime_rehash_policy, _Tr>;
template <typename _Key, typename _Tp,
typename _Hash = hash<_Key>,
typename _Pred = equal_to<_Key>,
typename _Alloc = allocator<std::pair<const _Key, _Tp>>>
class unordered_multimap
{
typedef __ummap_hashtable<_Key, _Tp, _Hash, _Pred, _Alloc> _Hashtable;
_Hashtable _M_h;
template <typename _Pair>
__enable_if_t<is_constructible<value_type, _Pair &&>::value, iterator>
insert(_Pair &&__x)
{
return _M_h.emplace(std::forward<_Pair>(__x));
}
...
};