STL容器(三):deque

前言

deque是一个很好用的双端队列,在头部或尾部插入删除复杂度都为O(1) 。关于deque操作方面就不怎么提了,和 vector 差不多 。这篇文章主要记录下deque的底层结构,这才是它有趣的地方。

deque结构

包括三个部分:迭代器(iterator)、中控器(map)、缓冲区(实际储存地址)。它们的关系如下图所示。
在这里插入图片描述

中控器(map)

这个结构也叫map,但是和STL里的map不一样,对于它来说,它是一个二维指针,每个节点都是指向一块真正储存数据的地方(缓冲区)。在这里,map的节点是连续的,每个缓冲区也是连续的,但是缓冲区之间可能在隔离的地址上。

每当一个缓冲区存满数据,我们就用已有的未使用的map节点,指向一个新的缓冲区。若已经达到map的最大值,又要重新分配新的map内存,这点和vector很像。

在这里插入图片描述
看下它的代码结构,就比较清晰的分层,map是一个二维指针,每个指针又指向块缓冲区地址。

template<class T, class Alloc = alloc, size_t Bufsize = 0>
class deque{
	public:	//basic types
		typedef T value_type;
		typedef value_type* pointer;
		...
	protected:	//internal typedefs
		//pointer of pointer of T
		typedef pointer* map_pointer;
		
	protected:	//Data members
		map_pointer map;//中控器map
		size_type map_size;
		...
}

迭代器(iterator)

接下来说说很关键的一个部分:迭代器。
我们现在拥有中控器和缓冲区,现在想做到明确地知道访问着哪个节点,map的范围是多少,现在访问着缓冲区哪个数据等,就需要迭代器来提供帮助,因此想想如果是自己写,会给迭代器结构设置哪些成员呢 ?

下面是一种实现方式

template<class T, class Ref, class Ptr, size_t BufSiz>
struct _deque_iterator{ //没有继承 std::iterator
	typedef _deque_iterator<T, T&, T*, BufSiz> iterator;
	typedef _deque_iterator<T, const T&, const T*, BufSiz> const_iterator;
	static size_t buffer_size(){return _deque_buf_size(BufSiz,sizeof(T));}

	//没继承iterator,自行编写五个必要迭代器的响应类别
	typedef random_access_iterator_tag iterator_category;//(1)
	typedef T value_type;//(2)
	typedef Ptr pointer; //(3)
	typedef Ref reference; //(4)
	typedef size_t size_type;
	typedef ptrdiff_t difference_type;//(5)
	typedef T** map_pointer;//指向map
	
	typedef _deque_iterator self;
	
	//保持与容器的联结
	T* cur;		//所指的缓冲区当前访问元素
	T* first;	//所指的缓冲区头
	T* last;	//所指的指向缓冲区尾
	map_pointer node;//管理map
	...
}

我们可以看到,决定缓冲区大小的函数 buffer_size(),调用 _deque_buf_size(), 后者是一个全局函数,有如下定义:

  • n不为0,传回n,buffer_size由用户定义
  • n 为0,buffer_size为自定义值
    • 如果sizeof(value_type)小于512,传回 512/sizeof(value_type)
    • 如果sizeof(value_type)不小于512,传回1
inline size_t _deque_buf_size(size_t n, size_t sz){
	return n != 0? n : (sz < 512 ?size_t(512/sz):size_t(1));
}

总结一下,迭代器关键就是 cur、first、end、node这四个指针。

例子

下面看一个例子体会下deque数据分配的操作。

情景
假设产生一个 deque< int >,并令其缓冲区大小为32 ,于是每个缓冲区可以容纳 32/sizeof(int) ,也就是 8个元素。
然后经过一些操作之后,我们拥有了20个元素,此时调用begin()和end()就会返回如图所示的两个迭代器。20个元素 等于 8*2 +4,也就是要三个缓冲区。
在这里插入图片描述> 然后更新所有值,并且填满后,在后面添加数据,情况如下
在这里插入图片描述
在前面增加数据,情况如下,注意cur指针位置
在这里插入图片描述

deque 操作

这方面真的和vector等很像。直接看书上的总结图吧。
在这里插入图片描述
它的 nonmodifying operation 。
在这里插入图片描述
在这里插入图片描述

参考书籍
《C++标准库-自学教程与参考手册》
《C++源码剖析》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值