The std::queue is implemented with a deque by default. std::deque has the subscript operator, operator[], and is probably implemented with arrays. So why doesn't std::queue have operator[]?
I realize you could have a queue with a list as the underlying container. (std::queue<int, std::list<int>>.) But even if that would make the subscript operator slow, is that really a good reason not to include it? That's the only reason I can think of that it is not included.
Because the definition of queue doesn't support such interface. Queue is a FIFO data structure which means First In First Out. Queue supports enqueue and dequeue operations.
Imagine of queue as pipe : you insert data into one end and from the other end you take it out - one by one. Inserting data is called enqueue and taking them out is called dequeue. The C++ standard library has std::queue which defines both these operations: push() is the name of enqueue operation, and dequeue operation has been splitted into two steps namely front() followed by pop(). The rationale why dequeue has been split into two steps is to give strong exception guarantee1.
Wikipedia explains this briefly,
A queue is a particular kind of collection in which the entities in the collection are kept in order and the principal (or only) operations on the collection are the addition of entities to the rear terminal position and removal of entities from the front terminal position. This makes the queue a First-In-First-Out (FIFO) data structure. In a FIFO data structure, the first element added to the queue will be the first one to be removed. This is equivalent to the requirement that once an element is added, all elements that were added before have to be removed before the new element can be invoked. A queue is an example of a linear data structure.
1. If you want to know how exacly it gives strong exception guarantee, then you can start another topic, because it's very long story, and requires lots of patience to understand it properly. I would suggest you to read Exceptional C++ by Herb Sutter for this.
It's a concept issue. In a queue, you add to the back and take from the front, not from the middle
The reason not to include it because a queue is a data structure with enqueue and dequeue operations, not random access. std::queue exists to adapt an existing container into a queue interface, so it only provides the queue interface.
If you want to use [] then use a deque with push_front and back/pop_back not a queue.
Why a double ended queue has it but not a queue doesn't make sense to me either.
Related
I have a program with a queue of strings. The requirements changed and now the output must be in alphabetical order. I am trying to sort the queue but am getting the error "no matching function call to 'begin(std::queue<std::cxx11__basic::string<char>>&)' and 'end(std::queue<std::cxx11__basic::string<char>>&)'
queue<std::string> lines = doWork();
std::sort(std::begin(lines), std::end(lines));
What's the best way to sort it? Would it be better to change from a queue to a vector or some other structure? The thing is the only operations needed is to add to end and remove from end.
Also I'm using Netbeans and it only displays the compile error messages when I hover over the red x so how can I copy and paste the message?
EDIT: I now understand queues can't be sorted. So what then is the best data structure to use? It only needs to be added to from one end, sorted and red linearally (from start to end)?
This is std::queue. It has no begin and end - that would defeat the purpose of the wrapper. Choose std::vector instead or use std::priority_queue.
std::queue has no begin and end, the order is always FIFO by definition.
Choose std::deque instead, it can be sorted and, unlike std::vector, has pop_front and offers better performance for FIFO operations.
Vectors and Linked Lists
Vectors are stored in memory serially, and therefore any element may be accessed using the operator[], just as in an array.
A linked list contains elements which may not be stored continuously in memory, and therefore a random element must be accessed by following pointers, using an iterator.
(You probably already knew this.)
Advantage of Priority Que
Recently I discovered the 'priority queue', which works kind of like a stack, but elements are push()-ed into the container, and this function places them in an order according to comparisons made with the operator<, I believe.
This suits me perfectly, as I am testing for events and placing them in the queue according to the time remaining until they occur. The queue automatically sorts them for me as I push() and pop() elements. (Popping does not affect the order.) I can write an operator< so this isn't a problem.
Issues I have not been able to resolve
There are three things which I need to be able to do with this event queue:
1:) Search the event queue for an item. I assume this can be done with an algorithm in the standard library? For example, 'find'? If not I can implement one myself, provided I can do point 2. (See below)
2:) Iterate over the queue. I think the default underlying container is std::vector... Is there a way to access random elements within the underlying vector? What if I choose to use std::deque instead? I need to do this to modify certain event parameters. (Events are placed in the queue.) As an example, I may need to process an event and then subtract a constant amount of time from each remaining event's 'time_to_event' parameter. I suspect this cannot be done due to this question.
3:) Remove an element from the queue. Sometimes when processing events, other events become invalidated, and therefore need to be removed.
Can points 1-3 be done? All the information I have on std::priority_queue has come from cplusplus.com, and so my default answer would be "no", there is no way to do any of these things. If I can't do all three things, then I guess I will have to write my own Priority Queue wrapper. (Oh boring)
No, you can't iterate over items in an std::priority_queue. All it supports is inserting items, and removing the highest priority item.
When you want more flexibility, you probably want to use std::make_heap to build the heap structure into your container, std::push_heap to add an item, and std::pop_heap to remove an item.
Since these are algorithms you apply to a container, you can still use the container's iterators as you see fit. Depending on how you modify the data in the heap, you may need to re-build the heap afterwards -- if you modify it in a way that the heap property no longer applies. You can test that with std::is_heap if you have any question.
Aside: many of us find http://www.cppreference.com more useful and accurate than the site you've linked.
Take a look at Boost.Heap. It looks like it addresses at least two of your issues (iteration and mutability).
I'm new to STL containers (and C++ in general) so thought I would reach out to the community for help. I basically want to have a priority_queue that supports constant iteration. Now, it seems that std::priority_queue doesn't support iteration, so I'm going to have to use something else, but I'm not sure exactly what.
Requirements:
Maintains order on insertion (like a priority queue)
Pop from top of list
Get const access to each element of the list (don't care about the order in the queue for this stage)
One option would be to keep a priority_queue and separately have an unordered_set of references, but I'd rather not have two containers floating around. I could also use a deque and search through for the right insertion position, but I'd rather have the container manage the sorting for me if possible (and constant-time insertion would be nicer than linear-time). Any suggestions?
There are two options that come to mind:
1) Implement your own iterable priority queue, using std::vector and the heap operation algorithms (see Heap Operations here).
2) derive (privately) from priority_queue. This gives you access to the underlying container via data member c. You can then expose iteration, random access, and other methods of interest in your public interface.
Using a std::vector might be enough as others already pointed, but if you want already-ready implementation, maybe use Boost.Heap (which is a library with several priority queue containers): http://www.boost.org/doc/libs/1_53_0/doc/html/heap.html
Boost is a collection of libraries that basically complete the standard library (which is not really big). A lot of C++ developers have boost ready on their dev computer to use it when needed. Just be careful in your choices of libraries.
You can use (ordered) set as a queue. set.begin() will be your top element, and you can pop it via erase(set.begin()).
Have you observed heap (std::make_heap) ? It hasn't order inside of queue, but has priority "pop from top of list" which you need.
Queue and Stack are a structures widely mentioned. However, in C++, for queue you can do it in two ways:
#include <queue>
#include <deque>
but for stack you can only do it like this
#include <stack>
My question is, what's the difference between queue and deque, why two structures proposed? For stack, any other structure could be included?
Moron/Aryabhatta is correct, but a little more detail may be helpful.
Queue and stack are higher level containers than deque, vector, or list. By this, I mean that you can build a queue or stack out of the lower level containers.
For example:
std::stack<int, std::deque<int> > s;
std::queue<double, std::list<double> > q;
Will build a stack of ints using a deque as the underlying container and a queue of doubles using a list as the underlying container.
You can think of s as a restricted deque and q as a restricted list.
All that is necessary is that the lower level container implements the methods needed by the higher level container. These are back(), push_back(), and pop_back() for stack and front(), back(), push_back(), and pop_front() for queue.
See stack and queue for more detail.
With respect to the deque, it is much more than a queue where you can insert at both ends. In particular, it has the random access operator[]. This makes it more like a vector, but a vector where you can insert and delete at the beginning with push_front() and pop_front().
See deque for detail.
Queue: you can insert only in one end and remove from the other.
Deque: you can insert and remove from both ends.
So using a Deque, you can model a Queue as well as a Stack.
Hint:
Deque is short for "Double ended queue".
deque is a container template. It satisfies the requirements for a sequence with random-access iterators, much like a vector.
queue is not a container at all, it is an adaptor. It contains a container and provides a different, more specific interface. Use queue when you want to remember (or remind) to avoid operations besides push[_back] and pop[_front], front and back, size and empty. You can't look at elements inside the queue besides the first and last, at all!
In the C++ library, both std::stack and std::queue are implemented as container adapters. That means they provide the interface of a stack or a queue respectively, but neither is really a container in itself. Instead, they use some other container (e.g. std::deque or std::list to actually store the data), and the std::stack class just has a tiny bit of code to translate push and pop to push_back and pop_back (and std::queue does roughly the same, but using push_back and pop_front).
A deque is a double-ended queue, which allows easy insertion/removal from either end. Queues only allow insertion in one end and retrieval from the other.
deque supports insert/pop from back & front
queue only supports insert to the back, and pop from the front. You know, a FIFO (first in first out).
A deque is double-ended. A queue isn't.
Priority queue dequeue happens according to some ordering (priority) comparison not the enqueue order.
For instance you might store timed events in one where you want to pull out the soonest event first and query for its scheduled time so you can sleep until that point in time.
Priority queues are often implemented using heaps.
by Mike Anderson here:
https://www.quora.com/What-is-the-difference-between-a-priority-queue-and-a-queue
In deque(double-ended queue) The element can be inserted from the back and removed from the rear(like in stack), but queue only allows removal from the front.
I can see the advantage of using two stacks if an array implementation is used since stacks are more easily implemented using arrays than queues are.
But if linked-lists are used, what is the advantage?
The act of popping the stack onto the queue increases overhead for both linked-list and array implementations.
It's a common way to implement a queue in functional programming languages with purely functional (immutable, but sharing structure) lists (e.g. Clojure, Haskell, Erlang...):
use a pair of lists to represent a queue where elements are in FIFO order in the first list and in LIFO order in the second list
enqueue to the queue by prepending to the second list
dequeue from the queue by taking the first element of the first list
if the first list is empty: reverse the second list and replace the first list with it, and replace the second list with an empty list
(all operations return the new queue object in addition to any possible return values)
The point is that adding (removing) an element to (from) the front of a purely functional list is O(1) and the reverse operation which is O(n) is amortised over all the dequeues, so it's close to O(1), thereby giving you a ~O(1) queue implementation with immutable data structures.
This approach may be used to build a lock-free queue using two atomic single-linked list based stacks, such as provided by Win32: Interlocked Singly Linked Lists.
The algorithm could be as described in liwp's answer, though the repacking step (bullet 4) can be optimized a bit.
Lock-free data structures and algorithms is a very exciting (to some of us) area of programming, but they must be used very carefully. In a general situation, lock-based algorithms are more efficient.
You can make an immutable queue using two immutable stacks.
But, if you just want a mutable queue, using two stacks is a great way to make it slower and more complicated than just using a linked list.
It's a good learning experience, but not a practical one.