基于环形缓冲区的deque实现方法
来源:互联网 发布:matlab中值滤波算法 编辑:程序博客网 时间:2024/05/29 03:17
众所周知,C++ STL中有一个叫做deque的容器,实现的是双端队列数据结构,这种队列允许同时从队列的首部和尾部插入和删除数据。
然而在STL中这种数据结构是用”分段连续”的物理结构实现的(可以参考侯捷老师的《STL源码剖析》)。网上分析STL中这种容器的文章很多,如:http://blog.csdn.net/baidu_28312631/article/details/48000123 (STL源码剖析——deque的实现原理和使用方法详解)就分析得很清楚。
个人认为STL的这种实现方法略有画蛇添足的嫌疑,不光增加了空间管理复杂度,而且使得iterator的随机访问变得低效(相对vector的iterator)。
侯捷老师在《STL源码剖析》第143页也提到:“对deque进行的排序操作,为了最高效率,可将deque先完整复制到一个vector身上,将vector排序后(利用STL sort算法),再复制回deque。”只因deque的Randon Access Iterator远不如vector的原生指针来得高效。
虽然作者暂时没弄明白为什么需要对“队列”做排序操作,即便如此,侯捷老师指出的copy-sort-copy思路,作者也是难苟同。
下面开始引出本文的主角——基于环形缓冲区的deque实现方法。
由于deque需要允许从队列头部插入和删除数据,如果像vector那样,为了在头部增删数据,每次都需要移动整个列表,显然是无法忍受的。
然而,利用环形链表思想,将vector的缓冲区看做是一个环形,则可以完美的在像vector一样连续的可增长的连续存储空间内实现deque。
数据结构定义如下:
class deque{ // pointer to range of storage array. //full storage is [_Myfirst, _Mylast) //buffer is cycle, that is to say, next(_Mylast-1)=_Myfirst, prev(_Myfirst)=_Mylast-1 pointer _Myfirst, _Mylast; //head and tail of deque //real data is [_Myhead,_Mytail) //so if tail<head, data is [_Myhead, _Mylast-1, _Myfirst, _Mytail) //head points to the first elem available for read //tail points to the first space available for write pointer _Myhead, _Mytail;}
其中[_Myfirst, _Mylast)记录了当前缓冲区的地址范围(即当前允许的最大队列长度)。
_Myhead和_Mytail记录了当前队列的头部和尾部的位置。
由于缓冲区是被看做是环形的,所以数据[_Myhead,_Mytail)可能有两种情况:
1. _Mytail >= _Myhead, 队列数据在[_Myhead,_Mytail)
2. _Mytail < _Myhead, 队列数据在[_Myhead, _Mylast-1, _Myfirst,_Mytail)
下面来详细讲述deque的4个操作:
void push_front(const value_type &_Val){ _Myhead = _Prev(_Myhead); _STDEXT unchecked_uninitialized_fill_n(_Myhead, 1, _Val, this->_Alval); if (_Myhead == _Mytail){//buffer full _Buy(2*capacity()); }}void push_back(const value_type &_Val){ _STDEXT unchecked_uninitialized_fill_n(_Mytail, 1, _Val, this->_Alval); _Mytail = _Next(_Mytail); if (_Myhead == _Mytail){//buffer full _Buy(2*capacity()); }}bool pop_front(){ if (empty()){ return false; } _Destroy(_Myhead); _Myhead=_Next(_Myhead); return true;}bool pop_back(){ if (empty()){ return false; } _Mytail = _Prev(_Mytail); _Destroy(_Mytail); return true;}bool empty() const{ return _Myhead == _Mytail;}
特别说明,当_Myhead == _Mytail的时候,表示队列为空。
可以看到,从头部push和pop的时候,实际只需要将_Myhead- -和_Myhead++
同理,从尾部push和pop的时候,只需要_Mytail++和_Mytail- -
当插入数据后,如果_Myhead==_Mytail,表示缓冲区已满,需要重新申请更大(2倍)的缓冲区,并把队列数据拷贝到新空间。
可以看到,以上代码在跟vector类似的连续空间上简单的实现了deque的所有关键操作,更让人欣慰的是,iterator(如果需要)是跟vector一样的原生指针,要在上面实现sort算法将是相当高效的,绝对不需要的copy-sort-copy。
我将代码放在了这里:
https://github.com/vipally/clab/blob/master/stl/deque/deque.hpp
欢迎有兴趣的筒子学习研究,如有不当的地方,敬请批评指正。
- 基于环形缓冲区的deque实现方法
- 环形缓冲区的实现
- 环形缓冲区的实现
- 环形缓冲区的实现
- 环形缓冲区的实现
- 环形缓冲区的实现原理
- 环形缓冲区的实现原理
- 环形缓冲区的c实现
- 环形缓冲区的实现原理
- 环形缓冲区的实现原理
- FIFO环形缓冲区的实现
- 环形缓冲区的实现原理
- 环形缓冲区的实现原理
- Qt实现环形缓冲区的两种方法
- 一个简单的环形缓冲区的实现
- 环形缓冲区的设计与实现
- 环形缓冲区的设计与实现
- 环形缓冲区的设计与实现
- 黄山市区到黄山风景区有多远,如何到黄山景区
- 无锁队列--基于linuxkfifo实现
- html()方法
- 隐式Intent 的匹配规则
- 在项目中成长(Make the Most of a Short-Term Assignment)
- 基于环形缓冲区的deque实现方法
- 你讨厌写selector背景了吗?手摸手教你封装个控件!
- 关于Struts2.3.31版本 datetimepicker不显示问题解决意见
- Android进阶之路 - Google下最简单的下拉刷新(SwipeRefreshLayout)
- ping 原理与ICMP协议
- caffe +MATLAB配置
- 堆和栈的区别
- Find K Pairs with Smallest Sums
- Post的简单用法