了解STL库中的squeue
来源:互联网 发布:java一对一聊天程序 编辑:程序博客网 时间:2024/06/06 03:52
【数据结构第二周作业文档】了解STL库中的squeue
queue单向队列与栈有点类似,一个是在同一端存取数据,另一个是在一端存入数据,另一端取出数据。单向队列中的数据是先进先出(First In First Out,FIFO)。在STL中,单向队列也是以别的容器作为底部结构,再将接口改变,使之符合单向队列的特性就可以了。单向队列一共6个常用函数:front()取队列头部数据、back()取队列尾部数据、push(elem)在队尾加入elem数据、pop()队头数据出队、empty()判断是否为空、size()判断数据个数。
下面就给出单向队列在VS2008中单向队列的源代码:
<span style="font-size:18px;">//VS2008中 queue的定义 MoreWindows整理(http://blog.csdn.net/MoreWindows) 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; queue() : c() { // construct with empty container } explicit queue(const _Container& _Cont) : c(_Cont) { // construct by copying specified container } bool empty() const { // test if queue is empty return (c.empty()); } size_type size() const { // return length of queue return (c.size()); } reference front() { // return first element of mutable queue return (c.front()); } const_reference front() const { // return first element of nonmutable queue return (c.front()); } reference back() { // return last element of mutable queue return (c.back()); } 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); } protected: _Container c; // the underlying container };</span>
可以看出,由于queue只是进一步封装别的数据结构,并提供自己的接口,所以代码非常简洁,如果不指定容器,默认是用deque来作为其底层数据结构的。
那么问题来了,deque又是什么样子的呢?
deque是双端队列,在队列头部和尾部可以快速的进行元素的插入和删除操作,相比vector而言有一定的优势,同时由于内部构造的设计,不存在vector那样扩充时带来的“配置新空间 / 移动旧数据 / 释放旧空间”问题。deque同时是STL中queue和stack的底层依赖组件。在查找的资料中可以看到,vector底层采用的是一个数组来实现,list底层采用的是一个环形的双向链表实现,而deque这种容器则采用的是两者相结合。所谓结合,并不是两种数据结构的结合,而是某些性能上的结合。通常我们知道vector支持随机访问,而list支持常量时间的删除,deque支持的是随机访问以及首尾元素的删除。
看到一个图用来说明deque底层所采用的数据结构非常直观:
这个结构就与我们所学的知识有点似曾相识的感觉了!貌似可以将这个数据结构变相地看成是一个二维数组,可将map看成是该二维数组的数组名。
当然deque的设计不会这么简单,在我搜的资料里看起来很高大上的就是它的一个迭代器设计:deque的迭代器的设计,主要是让其看起来像一个random access iterator,因此源码主要各种operator的重载。内部结构分为四个指针,分别为cur, first, last, node。在某一个时刻,迭代器肯定指向某个具体元素,而这个元素位于N段连续内存块中的某一块,其中node指向map结构中的一个节点(这个节点指向当前的内存块),first指向当前内存块的起始位置,cur指向当前内存块中的特定元素节点,last指向当前内存块的末尾位置。
好吧一图抵千言,这回是另一个地方扒下来的图。。感觉颜色很好看:
最后,对于deque的分析。deque的构造函数中会进行map结构的初始化操作,通过调用_M_initialize_map来实现,默认map的大小为8. 或者,当用户指定了每个内存块容纳的元素个数时,根据每个内存块默认的大小,算出需要多少个map指针,再加上2. 随后创建map需要的空间,并让start和finish尽可能落在map的中间位置,这样方便在头部和尾部都可以进行高效的扩充。deque支持push_back / pop_back / push_front / pop_font,实现机制都是类似的,这里以push_back为例进贴一段源码。(我找的这一段出处、准确性不保证哈哈,但是貌似也就这个好看懂点嘿嘿。)虽然很长,但是不难看出我们学的数据结构的影子呢~
// ============================================================================// deuqe class// ============================================================================template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >class deque : protected _Deque_base<_Tp, _Alloc> {public: // ========================================================================== // push_back() 操作 // ========================================================================== void push_back(const value_type& __t) { // 如果还有多余1个节点的空间,则直接构造,否则借助_M_push_back_aux实现 if (_M_finish._M_cur != _M_finish._M_last - 1) { construct(_M_finish._M_cur, __t); ++_M_finish._M_cur; } else _M_push_back_aux(__t); }protected: // ========================================================================== // push_back() 依赖的内部操作 // ========================================================================== void _M_push_back_aux(const value_type& __t) { value_type __t_copy = __t; // 确保map还有剩余空间 _M_reserve_map_at_back(); // 构造一块新的内存块,并填充map对应的节点 *(_M_finish._M_node + 1) = _M_allocate_node(); __STL_TRY { // 构造节点后更新指针 construct(_M_finish._M_cur, __t_copy); _M_finish._M_set_node(_M_finish._M_node + 1); _M_finish._M_cur = _M_finish._M_first; } __STL_UNWIND(_M_deallocate_node(*(_M_finish._M_node + 1))); } void _M_reserve_map_at_back (size_type __nodes_to_add = 1) { // 如果剩余空间不够,则需要扩充map了 if (__nodes_to_add + 1 > _M_map_size - (_M_finish._M_node - _M_map)) _M_reallocate_map(__nodes_to_add, false); } // 默认在尾部扩充 void _M_reallocate_map(size_type __nodes_to_add, bool __add_at_front) { // map中已经被填充的节点的个数 size_type __old_num_nodes = _M_finish._M_node - _M_start._M_node + 1; // 需要被填充的新的节点个数 size_type __new_num_nodes = __old_num_nodes + __nodes_to_add; _Map_pointer __new_nstart; // 如果map的大小比需要被填充的节点个数的两倍还大 // 则将map中start, finish区间往前移动即可 if (_M_map_size > 2 * __new_num_nodes) { __new_nstart = _M_map + (_M_map_size - __new_num_nodes) / 2 + (__add_at_front ? __nodes_to_add : 0); if (__new_nstart < _M_start._M_node) copy(_M_start._M_node, _M_finish._M_node + 1, __new_nstart); else copy_backward(_M_start._M_node, _M_finish._M_node + 1, __new_nstart + __old_num_nodes); } // 否则就需要重新配置一个新的map了 else { size_type __new_map_size = _M_map_size + max(_M_map_size, __nodes_to_add) + 2; _Map_pointer __new_map = _M_allocate_map(__new_map_size); __new_nstart = __new_map + (__new_map_size - __new_num_nodes) / 2 + (__add_at_front ? __nodes_to_add : 0); copy(_M_start._M_node, _M_finish._M_node + 1, __new_nstart); _M_deallocate_map(_M_map, _M_map_size); _M_map = __new_map; _M_map_size = __new_map_size; } _M_start._M_set_node(__new_nstart); _M_finish._M_set_node(__new_nstart + __old_num_nodes - 1); } // ...}
deque还有很多内部/外部函数,也都是围绕deque自身独特的设计进行操作。
总之,在STL库中,squeue和stack都是通过deque这个底层容器来实现的,只是进一步封装后提供了自己的接口,使其符合相应的要求。
0 0
- 了解STL库中的squeue
- STL 标准模板库 初步了解
- STL了解(初级)
- stl 初步了解
- STL学习 - queue了解
- 简单了解STL
- C++STL基本了解
- slurm(1): sinfo squeue scancel
- jsp中的stl标签库
- C/C++中的STL库
- STL函数库的简单了解
- 数据结构封装之《SQueue栈式队列》
- 数据结构封装之《SQueue栈式队列》
- linux中的glibc库与STL库
- STL标准库中的算法函数
- C++中STL库中的assign函数
- 标准库STL中的map和set
- STL标准库中的算法函数
- 第四周项目四(3)
- 常用网络访问方式的模板
- 两端移动输出一个字符串
- BP神经网络
- 读书笔记 | 从0到1:开启商业与未来的秘密
- 了解STL库中的squeue
- 设计模式之模板方法模式和策略模式
- fragment
- MIT研发的焦糖电池:未来手机将获更长续航和更轻薄的机身
- Comparable与Comparator的区别
- 机器学习之最大似然算法
- JSP
- 队列与优先队列
- hdu1402A * B Problem Plus