为什么默认情况下std :: stack使用std :: deque?


91

由于要在堆栈中使用容器的唯一操作是:

  • 背部()
  • 推回()
  • pop_back()

为什么默认容器是双端队列而不是向量?

难道双端队列重分配不会在front()之前提供元素的缓冲区,以便push_front()是有效的操作?这些元素不会浪费,因为它们永远不会在堆栈的上下文中使用吗?

如果没有用这种方式使用双端队列代替向量的开销,为什么priority_queue的默认向量也不是双端队列?(priority_queue需要front(),push_back()和pop_back()-与堆栈基本相同)


根据以下答案进行了更新:

似乎双端队列通常实现的方式是固定大小数组的可变大小数组。这使得它的增长速度比矢量(需要重新分配和复制)的增长速度快,因此对于像堆栈这样的所有元素而言,添加和删除元素都是可行的,双端队列可能是一个更好的选择。

priority_queue需要大量索引,因为每次删除和插入都需要运行pop_heap()或push_heap()。因为添加元素无论如何仍会摊销常量,所以这可能使vector成为更好的选择。


1
您的“更新”中的推理不太正确。向量通常比双端队列更快地添加和删除元素。deque可以更快地增加内存,而不是增加元素。
Mooing Duck 2015年

Answers:


75

随着容器的增长,向量的重新分配需要将所有元素复制到新的内存块中。增大双端队列会分配一个新块并将其链接到块列表-无需任何副本。

当然,您可以根据需要指定使用其他支持容器。因此,如果您有一个知道不会增长太多的堆栈,请告诉它使用向量而不是双端队列。


1
但是,当指向块的指针列表增加时,有时必须像矢量一样重新分配该列表。渐近地,效率的任何提高最多都是一个常数因子。正确进行推入和弹出操作所需的迭代器操作std::deque要比其复杂得多std::vector,并且这些操作的使用可能比重新分配的使用频率要高得多。我很难相信这在实践中std::deque会胜过std::vector
Marc van Leeuwen

@Michael Burr:那为什么不使用list,为什么deque呢?
bappak

关于您的@MarcvanLeeuwen说,您很难相信...您能说清楚点吗?您是说您现在认为自己std::deque确实有机会std::vector在练习中胜出,还是您仍然对此表示怀疑?谢谢。
aafulei

@fleix我看不出为什么我个人有一个更轻松的时间相信这样std::deque做会和std::vector在实际应用中一样好,为什么如此重要。但是,就其价值而言,我的个人经验是,我不需要堆栈和队列数据结构来完成一项繁琐而复杂的任务,而需要花很多时间在我的代码中。因此,我更关心小公司的行为而不是大公司的行为。而且双端队列在该处显得特别沉闷。我的首选是不使用任何一个,而是使用(自我实现的)单链表。但是你的里程可能会有所不同。
Marc van Leeuwen

12

有关vector和deque的相对优点,请参见Herb Sutter的“ 54周专家”

我想象priority_queue和queue之间的不一致仅仅是因为不同的人实现了它们。


2
priority_queue实际上并不使用push / pop_front,并且除第一个元素之外的元素的引用都会被堆操作无效。因此,与常规队列不同,双端队列没有任何好处可应用。
Potatoswatter

9
而且,priority_queue必须保持排序,因此随机访问的较高开销deque::iterator会带来更多问题。
Potatoswatter 2012年

1
@Potatoswatter:priority_queue保持“魔术顺序”,未排序。但是,您的观点是正确的。
Mooing Duck 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.