《STL源码剖析》深入分析序列式容器——deque
来源:互联网 发布:js 鼠标右键事件 编辑:程序博客网 时间:2024/05/21 10:31
1、deque的优缺点
欲抑先扬!先来看一下deque的优点:(1)头部插入删除操作,常数时间;(2)vector的假象三部曲“因空间不足a寻觅更大空间;b复制原数据;c释放源空间”在deque是不会发生的。因此也就不需要提供空间预留功能。
deque的缺点:它的迭代器并不是普通指针,其复杂度远远超出vector,这也直接影响了各个运算层面。deque实质上由一段一段的连续空间组成,如果有必要在前端或者尾端增加新空间,便配置一段定量的连续空间串接在前端或者尾端。
既然是分段连续空间,必然有中央控制。也就是说,为了维持整体连续的假象,数据结构的设计及迭代器前进后退等都相当繁琐。下图是deque 的结构设计中map和node-buffer(节点缓冲区)的关系简图。
既然是分段连续空间,必然有中央控制。也就是说,为了维持整体连续的假象,数据结构的设计及迭代器前进后退等都相当繁琐。下图是deque 的结构设计中map和node-buffer(节点缓冲区)的关系简图。
2、deque的迭代器
首先,deque的迭代器必须能够指出分段连续空间(缓冲区)在哪里;其次,它必须能够判断自己是否已经处在所在缓冲区的边缘,以便前进或者后退时跳跃至上一个或者下一个缓冲区。最后,为了能够跳跃到正确的分段缓冲区,他还必须随时和主控中心联系。
T* cur; //此迭代器所指之缓冲区中现行(current)的元素T* first; //此迭代器所指之缓冲区中头T* last; //此迭代器所指之缓冲区中尾(含备用空间)map_pointer node; //指向主控中心
//跳一个缓冲区void set_node(map_pointer new_node){node = new_node;first = *new_node;last = first + dirrerence_type(buffer_size());}//迭代器直接跳跃n个距离,实现随机存取self& operator+=(difference_type n) {difference_type offset = n + (cur - first);if (offset >= 0 && offset < difference_type(buffer_size())){//目标位置在同一个缓冲区内cur += n;}else {//目标位置在同一个缓冲区内difference_type node_offset =offset > 0 ? offset / difference_type(buffer_size()) : -difference_type((-offset - 1) / buffer_size()) - 1;//切换至正确的节点(缓冲区)set_node(node + node_offset);//切换至正确的元素cur = first + (offset - node_offset * difference_type(buffer_size()));}return *this;}3、deque中map的管理
我们先来看一下map中怎么配置的:
size_type num_nodes = num_elements / buffer_size() + 1; //需要节点数=(元素个数、每个分段节点(缓冲区)可容纳的元素个数)map_pointer nstart = map + (map_size - num_nodes) / 2; //为了使头尾的扩充能量一样大,令nstart和nfinish指向map的最中央区段map_pointer nfinish = nstart + num_nodes - 1;再来看一下map的“重新整治“:
//下面两个操作判断什么时候map需要整治void reserve_map_at_back (size_type nodes_to_add = 1) { if (nodes_to_add + 1 > map_size - (finish.node - map)) //map的尾端备用空间不足 reallocate_map(nodes_to_add, false);}void reserve_map_at_front (size_type nodes_to_add = 1) { if (nodes_to_add > start.node - map) //map的前端备用空间不足 reallocate_map(nodes_to_add, true);}//下面操作具体执行map的”重新整治“template <class T, class Alloc, size_t BufSize>void deque<T, Alloc, BufSize>::reallocate_map(size_type nodes_to_add, bool add_at_front) { size_type old_num_nodes = finish.node - start.node + 1; size_type new_num_nodes = old_num_nodes + nodes_to_add; map_pointer new_nstart; if (map_size > 2 * new_num_nodes) { new_nstart = map + (map_size - new_num_nodes) / 2 + (add_at_front ? nodes_to_add : 0); if (new_nstart < start.node) copy(start.node, finish.node + 1, new_nstart); else copy_backward(start.node, finish.node + 1, new_nstart + old_num_nodes); } else { //配置一块空间,准备给新的map使用 size_type new_map_size = map_size + max(map_size, nodes_to_add) + 2; map_pointer new_map = map_allocator::allocate(new_map_size); new_nstart = new_map + (new_map_size - new_num_nodes) / 2 + (add_at_front ? nodes_to_add : 0); //拷贝原map内容 copy(start.node, finish.node + 1, new_nstart); //释放原map map_allocator::deallocate(map, map_size); //设定新map的起始地址和大小 map = new_map; map_size = new_map_size; } //重新设定迭代器start和finish start.set_node(new_nstart); finish.set_node(new_nstart + old_num_nodes - 1);}4、deque的元素操作
(1)push_back() 操作
void push_back(const value_type& t){ if (finish.cur != finish.last - 1) { //最后缓冲区尚有两个及两个以上的元素备用空间 construct(finish.cur, t); //直接在备用空间上构造元素 ++finish.cur; //调整最后缓冲区的使用状态 } else //最后缓冲区只剩一个元素备用空间 push_back_aux(t); }//只有finish.cur = finish.last - 1时才会被调用template <class T, class Alloc, size_t BufSize>void deque<T, Alloc, BufSize>::push_back_aux(const value_type& t) { value_type t_copy = t; reserve_map_at_back(); //调用上述的map的重新整治操作 *(finish.node + 1) = allocate_node(); //配置一个新的分段缓冲节点 __STL_TRY { construct(finish.cur, t_copy); //针对新的元素设值 finish.set_node(finish.node + 1); //改变finish,令其指向新节点 finish.cur = finish.first; //设定finish的状态 } __STL_UNWIND(deallocate_node(*(finish.node + 1)));}
(2)push_front()操作
void push_front(const value_type& t) { if (start.cur != start.first) { //第一缓冲区尚元素备用空间 construct(start.cur - 1, t); //直接在备用空间上构造元素 --start.cur; //调整第一缓冲区的使用状态 } else push_front_aux(t); //第一缓冲区已无元素备用空间 }template <class T, class Alloc, size_t BufSize>void deque<T, Alloc, BufSize>::push_front_aux(const value_type& t) { value_type t_copy = t; reserve_map_at_front(); //调用上述的map的重新整治操作 *(start.node - 1) = allocate_node(); __STL_TRY { start.set_node(start.node - 1); start.cur = start.last - 1; construct(start.cur, t_copy); }# ifdef __STL_USE_EXCEPTIONScatch(...) { //若非全部成功,就一个不留 start.set_node(start.node + 1); start.cur = start.first; deallocate_node(*(start.node - 1)); throw; }# endif /* __STL_USE_EXCEPTIONS */}
0 0
- 《STL源码剖析》深入分析序列式容器——deque
- STL源码剖析——序列容器之deque
- 《STL源码剖析》深入分析序列式容器——vector
- 《STL源码剖析》学习笔记之四——序列式容器(deque之一)
- STL源码剖析之序列容器deque
- STL源码剖析 - 第4章 序列式容器 - deque
- STL源码剖析-序列式容器之deque
- STL源码剖析—序列容器
- STL源码剖析——序列式容器
- 【STL源码剖析读书笔记】【第4章】序列式容器之deque
- STL源码笔记(11)—序列式容器之deque(一)
- STL源码笔记(12)—序列式容器之deque(二)
- stl之序列容器——deque
- STL学习笔记——序列式容器deque
- STL序列式容器 - deque
- 《stl源码剖析》--序列式容器
- 【STL源码剖析】序列式容器
- STL源码剖析——deque
- java基础之static关键字
- 可以充放电2000次的锂空气电池
- 事务的四大特性
- Android文件下载之 搭建本机tomcat 服务器
- newInstance和new的区别
- 《STL源码剖析》深入分析序列式容器——deque
- 树莓派wifi配置
- 【bzoj4305】数列的GCD
- [TwistedFate]NSArray NSNumber NSValue
- 使用 CXF 做 webservice 简单例子
- 红黑树与平衡二叉树区别?
- codevs1081线段树练习2(树状数组)
- 数据结构例程——应用图的深度优先遍历思路求解问题
- matlab符号语言还未消化的语句