112

Since the only operations required for a container to be used in a stack are:

  • back()
  • push_back()
  • pop_back()

Why is the default container for it a deque instead of a vector?

Don't deque reallocations give a buffer of elements before front() so that push_front() is an efficient operation? Aren't these elements wasted since they will never ever be used in the context of a stack?

If there is no overhead for using a deque this way instead of a vector, why is the default for priority_queue a vector not a deque also? (priority_queue requires front(), push_back(), and pop_back() - essentially the same as for stack)


Updated based on the Answers below:

It appears that the way deque is usually implemented is a variable size array of fixed size arrays. This makes growing faster than a vector (which requires reallocation and copying), so for something like a stack which is all about adding and removing elements, deque is likely a better choice.

priority_queue requires indexing heavily, as every removal and insertion requires you to run pop_heap() or push_heap(). This probably makes vector a better choice there since adding an element is still amortized constant anyways.

Greg Rogers
  • 35,641
  • 17
  • 67
  • 94
  • 2
    The reasoning in your 'update' isn't quite right. vector normally adds and removes elements from the end _faster_ than a deque. deque is faster for _growing memory_, not pushing elements. – Mooing Duck Feb 12 '15 at 17:38

2 Answers2

87

As the container grows, a reallocation for a vector requires copying all the elements into the new block of memory. Growing a deque allocates a new block and links it to the list of blocks - no copies are required.

Of course you can specify that a different backing container be used if you like. So if you have a stack that you know is not going to grow much, tell it to use a vector instead of a deque if that's your preference.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • 2
    But when the list of pointers to blocks grows, this list must occasionally be reallocated just like a vector must; asymptotically, any gain in efficiency is by a constant factor at best. And iterator manipulation needed to do push and pop correctly is much more complicated for `std::deque` than it is for `std::vector`, and these operations are likely to be used much more frequently than reallocations. I have a hard time believing that `std::deque` would ever beat `std::vector` in practice. – Marc van Leeuwen Aug 28 '18 at 09:49
  • 2
    @Michael Burr: Then why not use `list`, why `deque`? – bappak Jan 28 '19 at 02:28
  • @MarcvanLeeuwen regarding you say you have a hard time believing ... could you please make a clear standpoint? do you mean you're now believing `std::deque` does have a chance to beat `std::vector` in practice, or do you mean you still doubt it? thanks. – aafulei Feb 17 '19 at 11:11
  • @fleix I don't see why it is so important whether I personally have an easier time believing that `std::deque` will do as well as `std::vector` in practical applications. But for what its worth, my personal experience is that I need stack and queue data structures not for one large and complexity-crucial task, but for many small occasions sprinkled through my code. As such I care more about behaviour in the small than in the large; and deque shines particularly dull there. My preference is to use neither, but (self-implemented) singly linked lists instead. But you mileage may vary. – Marc van Leeuwen Feb 18 '19 at 10:51
13

See Herb Sutter's Guru of the Week 54 for the relative merits of vector and deque where either would do.

I imagine the inconsistency between priority_queue and queue is simply that different people implemented them.

James Hopkin
  • 13,797
  • 1
  • 42
  • 71
  • 3
    priority_queue doesn't actually use push/pop_front, and references to elements besides the first are invalidated by the heap operations. So, none of the benefits of deque would apply, unlike the case of a regular queue. – Potatoswatter Dec 23 '09 at 08:18
  • 9
    Also, `priority_queue` must remain sorted, so the higher overhead of randomly accessing `deque::iterator` is more problematic. – Potatoswatter Jun 19 '12 at 05:27
  • 2
    @Potatoswatter: `priority_queue` has a "magic order" that's maintained, it's not sorted. However, your point stands. – Mooing Duck Feb 12 '15 at 17:40