Why is not possible to have a queue implemented as a vector? - c++

What are the drawbacks of using a std::vector for simulating a queue? I am naively thinking that push_back is used for push and for pop one just stores the position of the first element and increments it. Why does not std::queue allow a std::vector implementation like this in principle (I know the reason is it has no push_front method, but maybe there is something deeper that makes it slow this way)? Thank you for helping.

Why does not std::queue allow a std::vector implementation like this
std::queue is a simple container adapter. It works by delegating pop function to the pop_front function of the underlying container. Vector has no pop front operation, so std::queue cannot adapt it.
but maybe there is something deeper that makes it slow this way
Pushing and popping from the front of the vector is slow because it has to shift all elements which has linear cost. This is why vector doesn't provide pop_front.
stores the position of the first element and increments it.
It's possible to implement a container that does store the position of first element within a buffer, but vector is not an implementation of such container. Storing that position has an overhead that vector doesn't need to pay, and so it doesn't.

Related

Efficieny of stl vector and queue

I want to implement a program using either vector or queue data structure. The function requires frequently pushing and popping some elements (e.g. 8 elements) from the data structure to process these elements, and finally the data structure will be empty. The processing order doesn't matter so both vector and queue are ok. I want to know which one has higher efficiency if I need to frequently push and pop from it. Thank you.
std::queue isn't a container. It is a container adapter. By default, it adapts std::deque.
The function requires frequently pushing and popping some elements ... The processing order doesn't matter
This seems to imply that you can pop from the same end where you push (LIFO). In that case, another container adaptor would be appropriate: std::stack. It also adapts std::deque by default. There is no difference in efficiency of std::vector and the efficiency of std::stack that adapts std::vector. There can be a difference in using std::deque depending on the details of how you use it.

Can vector be resized bidirectionally?

Is there any function to resize a vector in both directions?Can we manipulate the pointer or the element from where it starts adding new empty elements?
Here is the entire interface of std::vector. It makes it very obvious there's no direct way to do what you ask, although you can reserve and then insert(begin,...) if you really want to (it has linear complexity, so is usually avoided).
The usual advice would be to use std::deque instead, since it's specifically designed for this operation.
Yes, you can insert elements to the front of the vector using insert:
vec.insert(vec.begin(), numer_of_elements_to_insert, {});
Note, however, that front-inserting into a vector is very inefficient, because it will require moving all the current elements in the vector past the newly inserted ones. If you need a double-ended container, look into std::deque.

Keeping constant number of elements in vector

I am trying to figure out the fastest way to keep constant number of elements in vector (or maybe there is some ready-made structure that do it automatically).
In my app I am adding multiple elements to the vector and I need to do it fast. Because of vector's self resizing at some point it is significantly decreasing overall application speed. What I was thinking about is to do something like this:
if(my_vector.size() < 300)
my_vector.push_back(new_element);
else
{
my_vector.pop_front();
my_vector.push_back(new_element);
}
but after first few tests I've realized that it might not be the best solution, because I am not sure if pop_front() and later push_back() doesn't still need to resize at some point.
Is there any other solution for this?
Use a std::queue. Its underlying container is a std::deque, but like a stack a queue's interface is specifically for FIFO operations (push_back, pop_front), which is exactly what you're doing in your situation. Here's why a deque is better for this situation:
The storage of a deque is automatically expanded and contracted as
needed. Expansion of a deque is cheaper than the expansion of a
std::vector because it does not involve copying of the existing
elements to a new memory location.
The complexity (efficiency) of common operations on deques is as
follows:
Random access - constant O(1)
Insertion or removal of elements at the end or beginning - constant O(1)
To implement a fixed-size container with push_back and pop_front and minimal memory shuffling, use a std::array of the appropriate size. To keep track of things you'll need a front index for pushing elements and a back index for popping things. To push, store the element at the location given by front_index, then increment front_index and take the remainder modulo the container size. To pop, read the element at the location given by back_index, and adjust that index the same way you did front_index. With that in place, the code in the question will do what you need.
You just need to reserve the capacity to a reasonable number. The vector will not automatically shrink. So it only will grow and, possibly, stop at some point.
You might be also interested in the resize policies. For example Facebook made a substantial research and created own implementation of the vector - folly::fbvector which has better performance than std::vector

How do I efficiently copy an entire queue to a vector/an array in C++?

How do I efficiently copy an entire queue to a vector/an array in C++?
say I have a std::queue and at some point I want to copy it to a vector/an array and then sort it.
Thanks for everyone's answers.
What I really want to do is to create a window with a fix length and at some point i need to copy all the elements inside this window and sort them. the window is moving and there are new data coming in through another interface so i want to use queue. is there any better implementations?
You wrote:
What I really want to do is to create a window with a fix length and at some point i need to copy all the elements inside this window and sort them. the window is moving and there are new data coming in through another interface so i want to use queue.
I suggest to take a step back, and reconsider whether you really want to use a queue. I suppose you want it because you
want to expose a minimal interface to the other component which adds data to the queue.
efficient addition/removal of elements at the front/back (to implement the 'fixed width window' concept)
an efficient way to access the data visible in the window sorted
Unfortunately, std::queue isn't very suitable for (3). Hence, I'd suggest to look for something which addresses (2) and (3), and then consider writing a wrapper of some sort (maybe a plain function which just adds an element to the queue will do?) to implement (1).
For instance, I'd consider using a plain std::deque. It can add/remove elements from the beginning/end of the queue in constant time. It's also very easy to get a sorted view on the window, e.g. if copying the elements of the queue is cheap you could use std::sort like:
std::vector<Elem> sortedView( queue.begin(), queue.end() );
std::sort( sortedView.begin(), sortedView.end() );
...you could of course also do something more clever by not copying the data but rather creating a vector of iterators into the queue, or by using a different sorting algorithm like partial_sort.
If you just want to keep a sorted queue, take a look at priority_queue.
Honestly, the best option is to use the right STL data structure from the start. If you will want to sort the data, a std::queue is not the right data structure.
Consider using a map (or perhaps a hash map). Typical implementations of maps actually build the map sorted, with lookups being performed in O(ln) time. You can still iterate sequentially through a map too, if you really want to.
The only way to access std::queue elements is using a combination of front, back, push, pop since std::queue has no iterators. (In order to be able to use iterators, you should use the underlying container (e.g. std::deque) directly, instead of std::queue.
Since you want to make a copy (presumably leaving the elements in the queue as they were), you can push elements back into the queue after you pop them.
Also, since you know the size of the queue, you can use vector::reserve to prevent expensive memory reallocations triggered by vector::push_back.
So
std::vector<int> V;
std::queue<int> Q;
V.reserve(Q.size());
for(size_t numPos = 0; numPops < Q.size(); ++numPops) {
V.push_back(Q.front());
Q.pop();
Q.push(V.back());
}
std::sort(V.begin(), V.end());

Can I Use C++ vector insted of queue for FIFO order

Hi all Can I use vector instead of queue ?. I just want to push and pop to and from memory using different thread . And also I need to delete data after pop. Is there any advantage using vector over queue ?
Thanks in advance....
It isn't wise, because a queue is FIFO, so you need to pop from the opposite end that you push into. For this, the structure to use is std::deque, which is the structure that std::queue uses under the hood by default.
A vector is analogous to a stack not to a queue. You may only push and pop from one side not push from one and pop from the other. A vector will give you the capability to access arbitrary element by its index in constant time but will not be able to efficiently remove elements from its beginning.
Using vector for queue will force you to insert or delete elements from the first position of vector. The vector is contained as a single block of memory and such operation is costly. Queue may be implemented more efficiently.
You "can" use a vector over a queue, if the queue lifetime is short or if you know the maximum size of your queue. Just use a vector, push_back in it, and keep an index of where your "head" is.
For exemple if i push back 3 elements, and i want to pop one, i'll just increment my "head" index by one.
This technique as been explained by Chandler Carruth in this video:
https://youtu.be/fHNmRkzxHWs?t=2541
If you really need a vector for a FIFO, you may use insert() and pop_back().
std::vector<glm::vec3> m_vertices;
glm::vec3 point1 = glm::vec3();
glm::vec3 point2 = glm::vec3();
m_vertices.insert(m_vertices.begin(), point1) ;
m_vertices.pop_back();
m_vertices.insert(m_vertices.begin(), point2);
I have a similar use case, a difference being that I only need to populate the 'queue' once, then I need to consume all the elements in the same order they were added, after which I discard the queue.
Anyone having a similar case can simply
use a vector
fill it with a series of push_back() calls
then use the entries in normal order (from begin() to end())
then just clear() the vector
I've not tested it yet, but will try it soon.