目录
10,unordered_map、unordered_multimap、unordered_set、unordered_multiset
1,class _Alloc = allocator<_Ty>
2,class _Container = deque<_Ty>
5,class _Keyeq = equal_to<_Kty>
一,容器
1,vector
(1)_Vector_val
template<class _Val_types>
class _Vector_val
: public _Container_base
{ // base class for vector to hold data
public:
using value_type = typename _Val_types::value_type;
using size_type = typename _Val_types::size_type;
using difference_type = typename _Val_types::difference_type;
using pointer = typename _Val_types::pointer;
using const_pointer = typename _Val_types::const_pointer;
using reference = value_type&;
using const_reference = const value_type&;
_Vector_val()
: _Myfirst(),
_Mylast(),
_Myend()
{ // initialize values
}
pointer _Myfirst; // pointer to beginning of array
pointer _Mylast; // pointer to current end of sequence
pointer _Myend; // pointer to end of array
};
这里面只存了指针
(2)_Vector_alloc
template<class _Alloc_types>
class _Vector_alloc
{ // base class for vector to hold allocator
public:
using _Alty = typename _Alloc_types::_Alty;
using _Alty_traits = typename _Alloc_types::_Alty_traits;
using _Alproxy = _Rebind_alloc_t<_Alty, _Container_proxy>;
using _Alproxy_traits = allocator_traits<_Alproxy>;
using _Val_types = typename _Alloc_types::_Val_types;
using size_type = typename _Val_types::size_type;
using difference_type = typename _Val_types::difference_type;
using pointer = typename _Val_types::pointer;
using const_pointer = typename _Val_types::const_pointer;
using iterator = _Vector_iterator<_Vector_val<_Val_types>>;
using const_iterator = _Vector_const_iterator<_Vector_val<_Val_types>>;
//一堆函数
private:
_Compressed_pair<_Alty, _Vector_val<_Val_types>> _Mypair;
};
这是分配器,有分配内存相关的操作,里面还存放着vector的指针
(3)vector
template<class _Ty,
class _Alloc = allocator<_Ty>>
class vector
: public _Vector_alloc<_Vec_base_types<_Ty, _Alloc>>
{ // varying size array of values
private:
using _Mybase = _Vector_alloc<_Vec_base_types<_Ty, _Alloc>>;
using _Alty = typename _Mybase::_Alty;
using _Alty_traits = typename _Mybase::_Alty_traits;
public:
static_assert(!_ENFORCE_MATCHING_ALLOCATORS || is_same_v<_Ty, typename _Alloc::value_type>,
_MISMATCHED_ALLOCATOR_MESSAGE("vector<T, Allocator>", "T"));
using value_type = _Ty;
using allocator_type = _Alloc;
using pointer = typename _Mybase::pointer;
using const_pointer = typename _Mybase::const_pointer;
using reference = _Ty&;
using const_reference = const _Ty&;
using size_type = typename _Mybase::size_type;
using difference_type = typename _Mybase::difference_type;
using iterator = typename _Mybase::iterator;
using const_iterator = typename _Mybase::const_iterator;
using reverse_iterator = _STD reverse_iterator<iterator>;
using const_reverse_iterator = _STD reverse_iterator<const_iterator>;
//一堆函数
}
继承了_Vector_alloc
获取数据指针:
_NODISCARD _Ty * data() noexcept
{ // return address of first element
return (_Unfancy_maybe_null(this->_Myfirst()));
}
_NODISCARD const _Ty * data() const noexcept
{ // return address of first element
return (_Unfancy_maybe_null(this->_Myfirst()));
}
2,list
(1)_List_buy
template<class _Ty,
class _Alloc>
class _List_buy
: public _List_alloc<_List_base_types<_Ty, _Alloc>>
{ // base class for list to hold buynode/freenode functions
public:
using _Mybase = _List_alloc<_List_base_types<_Ty, _Alloc>>;
using typename _Mybase::_Alnode;
using typename _Mybase::_Alnode_traits;
using typename _Mybase::_Nodeptr;
using typename _Mybase::_Node;
_List_buy()
: _Mybase()
{ // default construct
}
template<class _Any_alloc,
class = enable_if_t<!is_same_v<remove_cv_t<remove_reference_t<_Any_alloc>>, _List_buy>>>
_List_buy(_Any_alloc&& _Al)
: _Mybase(_STD forward<_Any_alloc>(_Al))
{ // construct from allocator
}
template<class... _Valty>
_Nodeptr _Buynode(_Nodeptr _Next, _Nodeptr _Prev, _Valty&&... _Val)
{ // allocate a node and set links and value
_Nodeptr _Pnode = this->_Buynode0(_Next, _Prev);
_Alnode& _Al = this->_Getal();
_TRY_BEGIN
_Alnode_traits::construct(_Al,
_STD addressof(_Pnode->_Myval),
_STD forward<_Valty>(_Val)...);
_CATCH_ALL
_Al.deallocate(_Pnode, 1);
_RERAISE;
_CATCH_END
return (_Pnode);
}
void _Freenode(_Nodeptr _Pnode)
{ // give node back
_Alnode& _Al = this->_Getal();
_Alnode_traits::destroy(_Al, _STD addressof(_Pnode->_Myval));
_Node::_Freenode0(_Al, _Pnode);
}
};
(2)list
template<class _Ty,
class _Alloc = allocator<_Ty>>
class list
: public _List_buy<_Ty, _Alloc>
{ // bidirectional linked list
public:
static_assert(!_ENFORCE_MATCHING_ALLOCATORS || is_same_v<_Ty, typename _Alloc::value_type>,
_MISMATCHED_ALLOCATOR_MESSAGE("list<T, Allocator>", "T"));
using _Mybase = _List_buy<_Ty, _Alloc>;
using _Node = typename _Mybase::_Node;
using _Nodeptr = typename _Mybase::_Nodeptr;
using _Alnode = typename _Mybase::_Alnode;
using _Alnode_traits = typename _Mybase::_Alnode_traits;
using value_type = typename _Mybase::value_type;
using allocator_type = _Alloc;
using size_type = typename _Mybase::size_type;
using difference_type = typename _Mybase::difference_type;
using pointer = typename _Mybase::pointer;
using const_pointer = typename _Mybase::const_pointer;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = typename _Mybase::iterator;
using const_iterator = typename _Mybase::const_iterator;
using _Unchecked_iterator = typename _Mybase::_Unchecked_iterator;
using _Unchecked_const_iterator = typename _Mybase::_Unchecked_const_iterator;
using reverse_iterator = _STD reverse_iterator<iterator>;
using const_reverse_iterator = _STD reverse_iterator<const_iterator>;
//一堆函数
}
3,deque
(1)_Deque_val
template<class _Val_types>
class _Deque_val
: public _Container_base12
{ // base class for deque to hold data
public:
using value_type = typename _Val_types::value_type;
using size_type = typename _Val_types::size_type;
using difference_type = typename _Val_types::difference_type;
using pointer = typename _Val_types::pointer;
using const_pointer = typename _Val_types::const_pointer;
using reference = value_type&;
using const_reference = const value_type&;
using _Mapptr = typename _Val_types::_Mapptr;
_Deque_val()
: _Map(),
_Mapsize(0),
_Myoff(0),
_Mysize(0)
{ // initialize values
}
size_type _Getblock(size_type _Off) const
{ // determine block from offset
// NB: _Mapsize and _DEQUESIZ are guaranteed to be powers of 2
return ((_Off / _DEQUESIZ) & (_Mapsize - 1));
}
_Mapptr _Map; // pointer to array of pointers to blocks
size_type _Mapsize; // size of map array, zero or 2^N
size_type _Myoff; // offset of initial element
size_type _Mysize; // current length of sequence
};
deque的数据模型是分段数组,每一段的长度是_DEQUESIZ,一共有_Mapsize段。
_Map是一个指针表,里面存放着最多_Mapsize个分段数组的地址。
所有分段数组逻辑上是连续的,形成一个逻辑上的大数组,调用_Getblock函数可以根据在这个大数组中的下标_Off,计算出所在分段数组是_Map中的第几个指针,从而完成随机寻址。
因为第0个元素在大数组中的下标是_Myoff,所以第k个元素在大数组中的下标就是k+_Myoff就出来了。
_Mapsize and _DEQUESIZ are guaranteed to be powers of 2 只是为了保证性能。
(2)_Deque_alloc
template<class _Alloc_types>
class _Deque_alloc
{ // base class for deque to hold allocator
public:
using _Alty = typename _Alloc_types::_Alty;
using _Alty_traits = typename _Alloc_types::_Alty_traits;
using _Alpty = typename _Alloc_types::_Alpty;
using _Alpty_traits = typename _Alloc_types::_Alpty_traits;
using _Alproxy = _Rebind_alloc_t<_Alty, _Container_proxy>;
using _Alproxy_traits = allocator_traits<_Alproxy>;
using _Val_types = typename _Alloc_types::_Val_types;
using size_type = typename _Val_types::size_type;
using difference_type = typename _Val_types::difference_type;
using pointer = typename _Val_types::pointer;
using const_pointer = typename _Val_types::const_pointer;
using _Mapptr = typename _Val_types::_Mapptr;
using iterator = _Deque_iterator<_Deque_val<_Val_types>>;
using const_iterator = _Deque_const_iterator<_Deque_val<_Val_types>>;
using _Unchecked_iterator = _Deque_unchecked_iterator<_Deque_val<_Val_types>>;
using _Unchecked_const_iterator = _Deque_unchecked_const_iterator<_Deque_val<_Val_types>>;
//一堆函数
private:
_Compressed_pair<_Alty, _Deque_val<_Val_types>> _Mypair;
};
(3)deque
template<class _Ty,
class _Alloc = allocator<_Ty>>
class deque
: public _Deque_alloc<_Deque_base_types<_Ty, _Alloc>>
{ // circular queue of pointers to blocks
private:
using _Mybase = _Deque_alloc<_Deque_base_types<_Ty, _Alloc>>;
public:
static_assert(!_ENFORCE_MATCHING_ALLOCATORS || is_same_v<_Ty, typename _Alloc::value_type>,
_MISMATCHED_ALLOCATOR_MESSAGE("deque<T, Allocator>", "T"));
using allocator_type = _Alloc;
using _Alty = typename _Mybase::_Alty;
using _Alty_traits = typename _Mybase::_Alty_traits;
using _Alpty = typename _Mybase::_Alpty;
using _Alpty_traits = typename _Mybase::_Alpty_traits;
using _Mapptr = typename _Mybase::_Mapptr;
using value_type = _Ty;
using size_type = typename _Mybase::size_type;
using difference_type = typename _Mybase::difference_type;
using pointer = typename _Mybase::pointer;
using const_pointer = typename _Mybase::const_pointer;
using reference = _Ty&;
using const_reference = const _Ty&;
using iterator = typename _Mybase::iterator;
using const_iterator = typename _Mybase::const_iterator;
using _Unchecked_iterator = typename _Mybase::_Unchecked_iterator;
using _Unchecked_const_iterator = typename _Mybase::_Unchecked_const_iterator;
using reverse_iterator = _STD reverse_iterator<iterator>;
using const_reverse_iterator = _STD reverse_iterator<const_iterator>;
enum {_EEN_DS = _DEQUESIZ}; // helper for expression evaluator
//一堆函数
}
4,stack
template<class _Ty,
class _Container = deque<_Ty> >
class stack
{ // LIFO queue implemented with a container
public:
typedef _Container container_type;
typedef typename _Container::value_type value_type;
typedef typename _Container::size_type size_type;
typedef typename _Container::reference reference;
typedef typename _Container::const_reference const_reference;
static_assert(is_same_v<_Ty, value_type>, "container adaptors require consistent types");
stack() _NOEXCEPT_COND(is_nothrow_default_constructible_v<_Container>) // strengthened
: c()
{ // construct with empty container
}
explicit stack(const _Container& _Cont)
: c(_Cont)
{ // construct by copying specified container
}
template<class _Alloc,
class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
explicit stack(const _Alloc& _Al)
_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, const _Alloc&>) // strengthened
: c(_Al)
{ // construct with allocator
}
template<class _Alloc,
class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
stack(const stack& _Right, const _Alloc& _Al)
: c(_Right.c, _Al)
{ // construct by copying specified container
}
template<class _Alloc,
class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
stack(const _Container& _Cont, const _Alloc& _Al)
: c(_Cont, _Al)
{ // construct by copying specified container
}
explicit stack(_Container&& _Cont)
_NOEXCEPT_COND(is_nothrow_move_constructible_v<_Container>) // strengthened
: c(_STD move(_Cont))
{ // construct by moving specified container
}
template<class _Alloc,
class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
stack(stack&& _Right, const _Alloc& _Al)
_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, _Container, const _Alloc&>) // strengthened
: c(_STD move(_Right.c), _Al)
{ // construct by moving specified container
}
template<class _Alloc,
class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
stack(_Container&& _Cont, const _Alloc& _Al)
_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, _Container, const _Alloc&>) // strengthened
: c(_STD move(_Cont), _Al)
{ // construct by moving specified container
}
void push(value_type&& _Val)
{ // insert element at beginning
c.push_back(_STD move(_Val));
}
template<class... _Valty>
decltype(auto) emplace(_Valty&&... _Val)
{ // insert element at beginning
#if _HAS_CXX17
return (c.emplace_back(_STD forward<_Valty>(_Val)...));
#else /* _HAS_CXX17 */
c.emplace_back(_STD forward<_Valty>(_Val)...);
#endif /* _HAS_CXX17 */
}
_NODISCARD bool empty() const
{ // test if stack is empty
return (c.empty());
}
_NODISCARD size_type size() const
{ // test length of stack
return (c.size());
}
_NODISCARD reference top()
{ // return last element of mutable stack
return (c.back());
}
_NODISCARD const_reference top() const
{ // return last element of nonmutable stack
return (c.back());
}
void push(const value_type& _Val)
{ // insert element at end
c.push_back(_Val);
}
void pop()
{ // erase last element
c.pop_back();
}
const _Container& _Get_container() const
{ // get reference to container
return (c);
}
void swap(stack& _Right) _NOEXCEPT_COND(_Is_nothrow_swappable<_Container>::value)
{ // exchange contents with _Right
_Swap_adl(c, _Right.c);
}
protected:
_Container c; // the underlying container
};
默认实现就是对deque的简单封装。
5,queue
template<class _Ty,
class _Container = deque<_Ty> >
class queue
{ // FIFO queue implemented with a container
public:
typedef _Container container_type;
typedef typename _Container::value_type value_type;
typedef typename _Container::size_type size_type;
typedef typename _Container::reference reference;
typedef typename _Container::const_reference const_reference;
static_assert(is_same_v<_Ty, value_type>, "container adaptors require consistent types");
queue() _NOEXCEPT_COND(is_nothrow_default_constructible_v<_Container>) // strengthened
: c()
{ // construct with empty container
}
explicit queue(const _Container& _Cont)
: c(_Cont)
{ // construct by copying specified container
}
template<class _Alloc,
class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
explicit queue(const _Alloc& _Al)
_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, const _Alloc&>) // strengthened
: c(_Al)
{ // construct with empty container, allocator
}
template<class _Alloc,
class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
queue(const _Container& _Cont, const _Alloc& _Al)
: c(_Cont, _Al)
{ // construct by copying specified container, allocator
}
template<class _Alloc,
class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
queue(const queue& _Right, const _Alloc& _Al)
: c(_Right.c, _Al)
{ // construct by copying _Right container, allocator
}
explicit queue(_Container&& _Cont)
_NOEXCEPT_COND(is_nothrow_move_constructible_v<_Container>) // strengthened
: c(_STD move(_Cont))
{ // construct by moving specified container
}
template<class _Alloc,
class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
queue(_Container&& _Cont, const _Alloc& _Al)
_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, _Container, const _Alloc&>) // strengthened
: c(_STD move(_Cont), _Al)
{ // construct by moving specified container, allocator
}
template<class _Alloc,
class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
queue(queue&& _Right, const _Alloc& _Al)
_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, _Container, const _Alloc&>) // strengthened
: c(_STD move(_Right.c), _Al)
{ // construct by moving _Right container, allocator
}
void push(value_type&& _Val)
{ // insert element at beginning
c.push_back(_STD move(_Val));
}
template<class... _Valty>
decltype(auto) emplace(_Valty&&... _Val)
{ // insert element at beginning
#if _HAS_CXX17
return (c.emplace_back(_STD forward<_Valty>(_Val)...));
#else /* _HAS_CXX17 */
c.emplace_back(_STD forward<_Valty>(_Val)...);
#endif /* _HAS_CXX17 */
}
_NODISCARD bool empty() const
{ // test if queue is empty
return (c.empty());
}
_NODISCARD size_type size() const
{ // return length of queue
return (c.size());
}
_NODISCARD reference front()
{ // return first element of mutable queue
return (c.front());
}
_NODISCARD const_reference front() const
{ // return first element of nonmutable queue
return (c.front());
}
_NODISCARD reference back()
{ // return last element of mutable queue
return (c.back());
}
_NODISCARD const_reference back() const
{ // return last element of nonmutable queue
return (c.back());
}
void push(const value_type& _Val)
{ // insert element at beginning
c.push_back(_Val);
}
void pop()
{ // erase element at end
c.pop_front();
}
const _Container& _Get_container() const
{ // get reference to container
return (c);
}
void swap(queue& _Right)
_NOEXCEPT_COND(_Is_nothrow_swappable<_Container>::value)
{ // exchange contents with _Right
_Swap_adl(c, _Right.c);
}
protected:
_Container c; // the underlying container
};
默认实现就是对deque的简单封装。
6,priority_queue
template<class _Ty,
class _Container = vector<_Ty>,
class _Pr = less<typename _Container::value_type> >
class priority_queue
{ // priority queue implemented with a _Container
public:
typedef _Container container_type;
typedef _Pr value_compare;
typedef typename _Container::value_type value_type;
typedef typename _Container::size_type size_type;
typedef typename _Container::reference reference;
typedef typename _Container::const_reference const_reference;
static_assert(is_same_v<_Ty, value_type>, "container adaptors require consistent types");
priority_queue()
_NOEXCEPT_COND(is_nothrow_default_constructible_v<_Container>
&& is_nothrow_default_constructible_v<value_compare>) // strengthened
: c(), comp()
{ // construct with empty container, default comparator
}
explicit priority_queue(const _Pr& _Pred)
_NOEXCEPT_COND(is_nothrow_default_constructible_v<_Container>
&& is_nothrow_copy_constructible_v<value_compare>) // strengthened
: c(), comp(_Pred)
{ // construct with empty container, specified comparator
}
priority_queue(const _Pr& _Pred, const _Container& _Cont)
: c(_Cont), comp(_Pred)
{ // construct by copying specified container, comparator
_STD make_heap(c.begin(), c.end(), comp);
}
template<class _InIt>
priority_queue(_InIt _First, _InIt _Last)
: c(_First, _Last), comp()
{ // construct by copying [_First, _Last), default comparator
_STD make_heap(c.begin(), c.end(), comp);
}
template<class _InIt>
priority_queue(_InIt _First, _InIt _Last, const _Pr& _Pred)
: c(_First, _Last), comp(_Pred)
{ // construct by copying [_First, _Last), specified comparator
_STD make_heap(c.begin(), c.end(), comp);
}
template<class _InIt>
priority_queue(_InIt _First, _InIt _Last, const _Pr& _Pred, const _Container& _Cont)
: c(_Cont), comp(_Pred)
{ // construct by copying [_First, _Last), container, and comparator
c.insert(c.end(), _First, _Last);
_STD make_heap(c.begin(), c.end(), comp);
}
template<class _Alloc,
class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
explicit priority_queue(const _Alloc& _Al)
_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, const _Alloc&>
&& is_nothrow_default_constructible_v<value_compare>) // strengthened
: c(_Al), comp()
{ // construct with empty container, allocator
}
template<class _Alloc,
class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
priority_queue(const _Pr& _Pred, const _Alloc& _Al)
_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, const _Alloc&>
&& is_nothrow_copy_constructible_v<value_compare>) // strengthened
: c(_Al), comp(_Pred)
{ // construct with empty container, comparator, allocator
}
template<class _Alloc,
class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
priority_queue(const _Pr& _Pred, const _Container& _Cont, const _Alloc& _Al)
: c(_Cont, _Al), comp(_Pred)
{ // construct by copying specified container, comparator, allocator
_STD make_heap(c.begin(), c.end(), comp);
}
template<class _Alloc,
class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
priority_queue(const priority_queue& _Right, const _Alloc& _Al)
: c(_Right.c, _Al), comp(_Right.comp)
{ // construct by copying _Right, allocator
}
priority_queue(const _Pr& _Pred, _Container&& _Cont)
: c(_STD move(_Cont)), comp(_Pred)
{ // construct by moving specified container, comparator
_STD make_heap(c.begin(), c.end(), comp);
}
template<class _InIt>
priority_queue(_InIt _First, _InIt _Last, const _Pr& _Pred, _Container&& _Cont)
: c(_STD move(_Cont)), comp(_Pred)
{ // construct by copying [_First, _Last), moving container
c.insert(c.end(), _First, _Last);
_STD make_heap(c.begin(), c.end(), comp);
}
template<class _Alloc,
class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
priority_queue(const _Pr& _Pred, _Container&& _Cont, const _Alloc& _Al)
: c(_STD move(_Cont), _Al), comp(_Pred)
{ // construct by moving specified container, comparator, allocator
_STD make_heap(c.begin(), c.end(), comp);
}
template<class _Alloc,
class = enable_if_t<uses_allocator_v<_Container, _Alloc>>>
priority_queue(priority_queue&& _Right, const _Alloc& _Al)
_NOEXCEPT_COND(is_nothrow_constructible_v<_Container, _Container, const _Alloc&>
&& is_nothrow_move_constructible_v<value_compare>) // strengthened
: c(_STD move(_Right.c), _Al), comp(_STD move(_Right.comp))
{ // construct by moving _Right, allocator
}
void push(value_type&& _Val)
{ // insert element at beginning
c.push_back(_STD move(_Val));
_STD push_heap(c.begin(), c.end(), comp);
}
template<class... _Valty>
void emplace(_Valty&&... _Val)
{ // insert element at beginning
c.emplace_back(_STD forward<_Valty>(_Val)...);
_STD push_heap(c.begin(), c.end(), comp);
}
_NODISCARD bool empty() const
{ // test if queue is empty
return (c.empty());
}
_NODISCARD size_type size() const
{ // return length of queue
return (c.size());
}
_NODISCARD const_reference top() const
{ // return highest-priority element
return (c.front());
}
void push(const value_type& _Val)
{ // insert value in priority order
c.push_back(_Val);
_STD push_heap(c.begin(), c.end(), comp);
}
void pop()
{ // erase highest-priority element
_STD pop_heap(c.begin(), c.end(), comp);
c.pop_back();
}
void swap(priority_queue& _Right)
_NOEXCEPT_COND(_Is_nothrow_swappable<_Container>::value
&& _Is_nothrow_swappable<_Pr>::value)
{ // exchange contents with _Right
_Swap_adl(c, _Right.c);
_Swap_adl(comp, _Right.comp);
}
protected:
_Container c; // the underlying container
_Pr comp; // the comparator functor
};
原理是用二叉堆实现优先队列。
7,_Tree
template<class _Traits>
class _Tree
: public _Tree_comp_alloc<_Traits>
{ // ordered red-black tree for map/multimap/set/multiset
// 省略
}
从注释看,这是红黑树的实现,map/multimap/set/multiset都是对它的封装。
红黑树分为不带重复元素的,可以带重复元素的,两种红黑树。
map/set是不带重复元素的红黑树,multimap/multiset是可以带重复元素的红黑树。
8,map、multimap、set、multiset
map
template<class _Kty,
class _Ty,
class _Pr = less<_Kty>,
class _Alloc = allocator<pair<const _Kty, _Ty>>>
class map
: public _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, false>>
{ // ordered red-black tree of {key, mapped} values, unique keys
//省略
};
随机访问:
mapped_type& operator[](key_type&& _Keyval)
{ // find element matching _Keyval or insert with default mapped
return (try_emplace(_STD move(_Keyval)).first->second);
}
multimap
template<class _Kty,
class _Ty,
class _Pr = less<_Kty>,
class _Alloc = allocator<pair<const _Kty, _Ty>>>
class multimap
: public _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, true>>
{ // ordered red-black tree of {key, mapped} values, non-unique keys
//省略
};
multimap不提供随机访问的方法。
红黑树只根据key作为比较大小的依据,不看value,所以不同的key映射同一个value显然是可以的。
multimap支持同一个key映射多个value,这其中还允许有重复的value,即multimap支持完全重复的pair。
set
template<class _Kty,
class _Pr = less<_Kty>,
class _Alloc = allocator<_Kty>>
class set
: public _Tree<_Tset_traits<_Kty, _Pr, _Alloc, false>>
{ // ordered red-black tree of key values, unique keys
//省略
};
multiset
template<class _Kty,
class _Pr = less<_Kty>,
class _Alloc = allocator<_Kty>>
class multiset
: public _Tree<_Tset_traits<_Kty, _Pr, _Alloc, true>>
{ // ordered red-black tree of key values, non-unique keys
//省略
};
怎么理解multi?
先写个demo测一下:
int main()
{
multimap<int,int> m;
m.insert({ 1,2 });
m.insert({ 1,3 });
m.insert({ 3,3 });
m.insert({ 1,2 });
for (auto it : m) {
cout << it.first << " " << it.second << endl;
}
multiset<int>s;
s.insert(2);
s.insert(3);
s.insert(2);
for (auto x : s) {
cout << x << endl;
}
return 0;
}
输出:
1 2
1 3
1 2
3 3
2
2
3
也就是说,multiset是带重复元素的红黑树,所以2 3 2会变成2 2 3,
而multimap显然是这4个里面最复杂的,key由红黑树组成,所以前3个key是1 1 1,第4个key是2
但是{ 1,2 }{ 1,3 }{ 1,2 }这3个节点会保留顺序,不会排序,因为value是不带比较函数的。
也就是说,multimap相当于是每个键值对的值,其实都是一个线性表。
9,_Hash
template<class _Traits>
class _Hash
{ // hash table -- list with vector of iterators for quick access
public:
using key_type = typename _Traits::key_type;
using key_compare = typename _Traits::key_compare;
using value_compare = typename _Traits::value_compare;
//省略
_Traits _Traitsobj; // traits to customize behavior
_Mylist _List; // list of elements, must initialize before _Vec
_Myvec _Vec; // vector of list iterators, begin() then end()-1
size_type _Mask; // the key mask
size_type _Maxidx; // current maximum key value
};
C++哈希表用链接法处理冲突。
JAVA的哈希表是当链表长度达到阈值时自动转成红黑树。
10,unordered_map、unordered_multimap、unordered_set、unordered_multiset
这四个都是对_Hash的封装。
unordered_map
template<class _Kty,
class _Ty,
class _Hasher = hash<_Kty>,
class _Keyeq = equal_to<_Kty>,
class _Alloc = allocator<pair<const _Kty, _Ty>>>
class unordered_map
: public _Hash<_Umap_traits<_Kty, _Ty,
_Uhash_compare<_Kty, _Hasher, _Keyeq>, _Alloc, false>>
{ // hash table of {key, mapped} values, unique keys
//省略
};
unordered_multimap
template<class _Kty,
class _Ty,
class _Hasher = hash<_Kty>,
class _Keyeq = equal_to<_Kty>,
class _Alloc = allocator<pair<const _Kty, _Ty>>>
class unordered_multimap
: public _Hash<_Umap_traits<_Kty, _Ty,
_Uhash_compare<_Kty, _Hasher, _Keyeq>, _Alloc, true>>
{ // hash table of {key, mapped} values, non-unique keys
//省略
};
unordered_set
template<class _Kty,
class _Hasher = hash<_Kty>,
class _Keyeq = equal_to<_Kty>,
class _Alloc = allocator<_Kty>>
class unordered_set
: public _Hash<_Uset_traits<_Kty,
_Uhash_compare<_Kty, _Hasher, _Keyeq>, _Alloc, false>>
{ // hash table of key values, unique keys
//省略
};
unordered_multiset
template<class _Kty,
class _Hasher = hash<_Kty>,
class _Keyeq = equal_to<_Kty>,
class _Alloc = allocator<_Kty>>
class unordered_multiset
: public _Hash<_Uset_traits<_Kty,
_Uhash_compare<_Kty, _Hasher, _Keyeq>, _Alloc, true>>
{ // hash table of key values, non-unique keys
//省略
};
泛型哈希表的思路是二次哈希,首先把任意类型的key通过_Hasher映射成整数,再用_Hash处理整数的哈希存储问题。
可以把2个哈希函数看成复合函数,就变成了1个哈希函数,无论是谁有哈希冲突都无所谓,总体上肯定是有冲突的。
_Keyeq就是用来判断冲突的key是不是同一个key。
二,容器模板参数
除了容器中的元素本身类型的参数之外,还有如下参数。
1,class _Alloc = allocator<_Ty>(分配器)
2,class _Container = deque<_Ty>
3,class _Pr = less<typename _Container::value_type>
4,class _Hasher = hash<_Kty>
这是选择哈希函数,默认的是通用的hash函数。
hash函数的内部实现很粗暴,就是把数据强制转换成整数。
5,class _Keyeq = equal_to<_Kty>
这是哈希表中判断2个键是否相等的函数,默认的是通用的equal_to函数。
equal_to函数的内部实现很简单,就是调用==即可。
三,迭代器
1,traits
通用traits
template<class,
class = void>
struct _Iterator_traits_base
{ // empty for non-iterators
};
template<class _Iter>
struct _Iterator_traits_base<_Iter, void_t<
typename _Iter::iterator_category,
typename _Iter::value_type,
typename _Iter::difference_type,
typename _Iter::pointer,
typename _Iter::reference
>>
{ // defined if _Iter::* types exist
using iterator_category = typename _Iter::iterator_category;
using value_type = typename _Iter::value_type;
using difference_type = typename _Iter::difference_type;
using pointer = typename _Iter::pointer;
using reference = typename _Iter::reference;
};
template<class _Iter>
struct iterator_traits
: _Iterator_traits_base<_Iter>
{ // get traits from iterator _Iter, if possible
};
指针类型的
template<class _Ty,
bool = is_object_v<_Ty>>
struct _Iterator_traits_pointer_base
{ // iterator properties for pointers to object
using iterator_category = random_access_iterator_tag;
using value_type = remove_cv_t<_Ty>;
using difference_type = ptrdiff_t;
using pointer = _Ty *;
using reference = _Ty&;
};
template<class _Ty>
struct _Iterator_traits_pointer_base<_Ty, false>
{ // iterator properties for pointers to non-object
// not actually iterators, as no arithmetic is possible -> no members
};
template<class _Ty>
struct iterator_traits<_Ty *>
: _Iterator_traits_pointer_base<_Ty>
{ // get traits from pointer, if possible
};
iterator_category是允许的操作集,
value_type是数据的类型
difference_type表示2个迭代器的差值,其实就是有符号整数类型,ptrdiff_t也是有符号整数类型。
pointer 和 reference 是数据的指针类型和引用类型。
2,迭代器类型
对应的空结构体:
struct input_iterator_tag
{ // identifying tag for input iterators
};
struct output_iterator_tag
{ // identifying tag for output iterators
};
struct forward_iterator_tag
: input_iterator_tag
{ // identifying tag for forward iterators
};
struct bidirectional_iterator_tag
: forward_iterator_tag
{ // identifying tag for bidirectional iterators
};
struct random_access_iterator_tag
: bidirectional_iterator_tag
{ // identifying tag for random-access iterators
};
用显式的结构体来表达迭代器类型,可以直接用于函数重载。