C++:deque(双端队列)

一、deque

1.1 deque的原理介绍

**deque(双端队列):是一种双开口的“连续空间”的数据结构。**双开口的含义是:可以在头尾两端进行插入和删除操作,并且时间复杂度是O(1)的,与vector相比,头插效率高,不需要搬移元素;与list比较空间利用率高。

vector:连续的物理结构,优势:支持下标访问,劣势:扩容头部插入删除的效率低。

list:一块一块的分散结构,优势:按需申请释放任意位置插入删除的效率高,劣势:下标访问效率低,在标准库的实现中是不支持下标访问的。

以下是deque的图示:

deque并不是真正连续的空间,而是由一段断的连续的小空间拼接而成的,实际deque是类似于一个动态的二维数组的结构的,其底层结构如下图所示:

双端队列底层是一段假象的连续空间,实际上是分段连续的,为了维护其“整体连续”以及随机访问的假象,落在了deque的迭代器身上,因此deque的迭代器的实现比较复杂,如下图所示:

deque借助迭代器维持假象的连续结构的原理:

中控数组的本质就相当于一个指针数组,中控数组中的每个元素指向一个小数组,从而实现一个连续空间的假象,其实是有一段段小的连续空间通过中控数组联系起来的。

1.2 deque的缺陷

与vector比较,deque的优势是:头部插入和删除时,不用挪动元素,效率比较高,而且在扩容时也不需要挪动元素,因此效率是一定比vector高的。

与list比较 ,deque的底层是一个伪连续空间,空间利用率高,不需要存储额外字段。

致命缺陷deque不适合用来遍历,因为在遍历时deque的迭代器需要频繁的检测其是否移动到某段小空间的边界,导致效率低下,但是在序列式的场景下,可能要经常进行遍历,因此在实际中对于线性结构大多数的情况下还是优先使用vector和list,deque的引用并不多,deque作为stack和queue的底层数据结构是比较好的

二、为何选择deque作为stack和queue的默认容器

1,stack和queue是不需要进行遍历的(因此stack和queue是没有迭代器的),只需要固定的一端或者两端进行操作。

2,在stack中元素增长时,deque比vector的效率高(因为扩容时不需要进行挪动数据);queue中的元素增长时deque不仅效率高,而且内存使用率同样也高。

对于在作为stack和queue的底层容器是正好结合了deque的优点而且完美的避开了它的缺点。

三、deque的使用

3.1 stack的模拟实现:

template<class T, class Con = deque<T>>
//栈
class stack
{

public:
	//栈的构造
	stack() {}
	//push直接借助传入容器的push即可
	void push(const T& x)
	{
		c.push_back(x);
	}
	//pop借助容器的pop将栈顶元素即数组中的最后一个元素pop掉
	void pop()
	{
		c.pop_back();
	}
	//返回栈顶元素即数组的最后一个元素
	T& top()
	{
		return c.back();
	}

	const T& top()const
	{
		return c.back();
	}
	//返回栈内的元素个数,直接返回容器的size即可
	size_t size()const
	{
		return c.size();
	}
	//判断栈是否为空,直接判断容器是否为空即可
	bool empty()const
	{
		return c.empty();
	}

private:

	Con c;

};

3.2 queue的模拟实现:

template<class T, class Con = deque<T>>
//队列
class queue
{
public:
	//队列的构造
	queue() {}
	//进队列,先进先出,队尾进队头出,选择头插
	void push(const T& x)
	{
		c.insert(c.begin(), x);
	}
	//出队列尾删即可
	void pop()
	{
		c.pop_back();
	}
	//返回队尾元素,即返回容器的头
	T& back()
	{
		return c.front();
	}

	const T& back()const
	{
		return c.front();
	}
	//返回队头元素,即返回容器的尾
	T& front()
	{
		return c.back();
	}

	const T& front()const
	{
		return c.back();
	}
	//返回队列中的有效数据,即返回容器的size
	size_t size()const
	{
		return c.size();
	}
	//判断队列是否为空,即判断容器是否为空即可
	bool empty()const
	{
		return c.empty();
	}

private:

	Con c;

};

四、总结

1.deque 的结构,支持下标随机访问,偶尔使用还行,但是大量访问的效率远不及vector

2.deque的insert和erase是需要考虑挪动数据的,因此效率不高。

3.deque的头尾插入删除效率很高,STL库中的stack和queue的底层是基于deque实现的。

结论:deque作为stack和queue的底层容器是很适合的。

ector**

2.deque的insert和erase是需要考虑挪动数据的,因此效率不高。

3.deque的头尾插入删除效率很高,STL库中的stack和queue的底层是基于deque实现的。

结论:deque作为stack和queue的底层容器是很适合的。

  • 22
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凪よ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值