I have a queue with n elements in it and the front is at 0. I need to create a stack of these numbers with 0 at the top.
It can only be done with EnQueue, DeQueue, Push, and Pop, and constant storage. I dont need an answer so much as an idea of how I could approach this problem.
Please don't answer this for me, but just try to understand I'm new at programming and could just use an idea of what is a way this can be done.
Is it a Towers-of-Hanoi-like approach?
Does that only use a constant storage?
This isnt for homework, I just need some advice on how to proceed. My first idea, reversing the queue and then pushing it did not work. I even tried sketching out other situations with no avail. Then I wondered if dequeueing and pushing them all, then popping and enqueueing them all, then dequeue and push again.
Is this efficient?
Does this use constant storage?
I am still learning fundamental programming concepts. Please be nice! :)
What am I facing?
The biggest problem you are facing is that your two containers aren't directly compatible with each other.
A queue is normally a FIFO1 container, while a stack is LIFO2. This means that you cannot just copy the data in sequential order from your queue to your stack, since that will make the elements appear in the "wrong" order (following your description).
Another problem is that there is no good way (performance wise) to reverse a queue. A queue is a one-way container, internally an element only has to know about the next element in line, not about the previous one. This means that you cannot iterate through the queue starting at the back, and that iteration always is O(n).
The same problem is with your stack.
The things described earlier put together makes this quite a tedious problem, though there are solutions they aren't always the most straight forward.
Hints on how to solve this issue..
You'll need some sort of intermediate state to store your elements, or could we use the LIFO/FIFO properties of our containers to our advantage?
Below is an implementation which does what you want, if you don't want to know the answer to your question don't hover with your mouse over this gray area.
It will require some additional storage since space for an extra element will be allocated during copying from one container to another.. this is inevitable, though the storage is constant.
Remember that the copy-initialization can be optimized by using rvalue-references and move in C++11.
Can't seem to get syntax highlighting working inside a spoiler..
Sample implementation can be found here.
It takes advantage of the fact that a queue is FIFO and stack LIFO, by copying the data queue to stack, then stack to queue and finally queue to stack again we have effectively reversed the order of elements in a way that will match your description.
footnotes
1. FIFO = First In First Out
2. LIFO = Last In First Out
DeQueue everything from Queue, immediately Pushing each element to Stack. Now Pop everything from Stack, immediately EnQueueing to Queue. What's in Queue now?
Presuming your Queue and Stack hold fixed sized items, the above ahem subroutine certainly only uses constant additional storage: Only storage for 1 item is needed as each item transits from Queue to Stack or vice-versa.
Edit: As you point out, my subroutine reverses the content of the Queue. Having done so, it is fairly simple to drain the Queue into the Stack again to get the desired outcome.
And, as you point out, this requires transferring 3n = O(n) items, where n is the initial size of the Queue. Could you do better? I don't believe so, or at least not significantly. In some sense, without even a counter (which would take O(log n) > O(1) extra storage), the only reasonable thing to do is drain the queue into the stack or vice versa.
Related
Consider I have a min priority queue with the smallest value on the top, I hope to reduce the value on the top so that the property of the queue would still be maintained and time complexity would be O(1). How to do that?
I have seen the question here how to change the value of std::priority_queue top()?
Where take the value out, modify it and push it back basically would be O(logN) complexity, I wonder can I make use of the property of reducing the value so that there is no need to push the value back again?
The standard priority queue doesn't support changing the keys.
What you are looking for is something similar to another data structure called Indexed Priority Queue, often used by Dijkstra algorithm.
The Indexed Prioirty queue supports 2 more methods in it's API: increaseKey and decreaseKey enabling modifying the key's itself.
The STL doesnt define indexed priority queue. You'd probably need to implement one by yourself or look for some third party implementation.
I see the point of this question differently from others. Based on this question,
I have a min priority queue with the smallest value on the top, I hope to reduce the value on the top so that the property of the queue would still be maintained and time complexity would be O(1).
With std::priority_queue, you can't. We may try a hack like const_cast<int &>(pq.top()) = lesser_value_than_top. It could work in some implementations, but it is NOT safe.
So, I would like to suggest building your own PQ with an array-based heap, and you can just change the top's value without log(N) work, as long as it is a value equal or less than the current top.
this is a question regarding writing your own data structure programs (which appears to be called implementation I think?). I am using C++ to write.
When I did a stack assignment, popping something off the stack simply changed the index of the top variable as it was more about where the user can access items vs actually physically removing the item (it's not accessible once the top variable is changed, so my professor said these things don't actually need to be deleted/removed). Once top is moved down, there's more room for items on top.
In a queue, my understanding is that one dequeues from the front (first in, first out). When this happens, would all the remaining items need to be moved up one index?
For example, if I have a queue of 3, 5, 7 and I dequeue one, would I simply have an int variable called "front" that I increment from 0 to 1 so that front is now at the index for number 5? My concern is that by doing this, the queue will no longer be able to hold the max number of items, so I would think that I would move everyone down one index so that there is still room to add things at the back.
TLDR yes, I would say you should move the elements
Let's start from the beginning:
When I did a stack assignment, [...] my professor said these things
don't actually need to be deleted/removed
It's important (imho) to understand why the professor said this.
First you need to be aware that this strategy works only for element types that have a trivial destructor (e.g. basic data types like int). This is a restriction of your particular implementation of the stack. Another limitation of your stack is that is has a limiting max capacity. A proper queue structure like std::stack has none of these shortcomings. This is perfectly fine for your assignment because implementing a stack without those restrictions would involve dynamic memory allocations and/or advanced techniques like placement new (or use an underlying container that already does all of this like std::deque). But the point of the assignment is to teach you the concepts of stack. Learning one new thing can be difficult. Learning 3 new and unrelated complex things at the same time would be irresponsible. So that's why your professor said "these things don't actually need to be deleted/removed".
Now let's go to the queue structure. Regardless of your choice your queue still has the above two limitations: applicable only for types with trivial destructor and unable to deal with unlimited elements.
If you move the elements then your queue will have the limitation of a (relatively small) maximum capacity (just like the stack you implemented)
If you don't move the elements then your queue will be limited to a maximum number of push operations, regardless of the pop operations. Just like you identified. So when the maximum push operations have been reached you can't push into the queue anymore, even if you poped or pop elements out of it.
The latter one is obviously more limited then the former. But since you already are supposed to implement a queue with limited capabilities the question is if the more limited one and the most easy to implement is acceptable in your exercise or not. Only your professor can clarify this. He/she can say something along the lines: "I am only interested you learn the abstract concepts of the queue and such you can assume/imagine an infinite capacity; you just need to deal with the indices and the correctness of push/pop operations". Or he/she can except you move the elements since it might be something you are already supposed to know how to do. However I would recommend to implement the moves regardless because it is not that difficult and is an useful skill.
As noted in the comments there are other ways of implementing a queue, like a circular queue.
So, i'm coding one thing on c++, and i'm trying to implement a priority queue with pairing heaps. I want this priority to automatically increase over time, so that if the element (a class) has been in the heap for, say, 5 minutes, it's priority (a variable) is increased. And i have no clue how to make that happen.
I could implement a function which would check the duration for each element each set amount of time, but the problem is that it's pretty tough to check each and every element within a heap. So I think I need to do something withinin the elements, but I'm not sure what and how.
Is there any simple solution to that? I feel like i must be missing something, but if that's not the case, then I'd better drop this idea, because I have to finish this thing pretty soon.
UP: This program is meant for the human queue, so the reason for this idea is to not make people wait for too long. The priority is arbitrary, there are priority "levels" set for each element when it's added, so making the time the priority is not a solution for me.
You can add the elements to a linked list:
A new element is added to the end of the list
When the first element is in heap for 5 mins, its priority increased and it is moved to the end of the list.
This way you can check only the first element. Another advantage is that you can set the timer to the value the first element is to be checked in. That is, no need to do unnecessary periodical checks.
I am to write a C++ program that :
"Implements the vector ADT by means of an extendable array used in a circular fashion, so that insertions and deletions at the beginning and end run in constant time. (So not O(n)). Print the circular array before and after each insertion and deletion, You cannot use the STL."
This task seems very confusing to me. A std::vector is implemented using a dynamic array that is based off the concept of a stack, correct? Performing a deletion or insertion at the front seems to me that this should be implemented as a Queue or maybe a Dequeue, not a Vector. Also, a circular array would mean that when data is pushed onto an array that is Full, old data becomes overwritten, right? So when should I know to expand the vector's capacity?
If I'm not making sense here, Basically I need help in understanding how I should go about implementing a dynamic circular array..
Yes, this is a homework assignment. No, I do not expect anyone to provide code for me, I only wish for someone to give me a push in the right direction as to how I should think about implementing this. Thank you.
I think you are actually being asked to implement deque. The point of the "circularity" is that in normal vector you cannot add an element at the beginning since there is no free space and you would have to move all other elements to the right. So what you can do is you simulate a circle by putting the element to the end the base array and remember that's where the first element is.
Example: 2, 3, -, -, 1 where 1 is first and 3 is last
So, basically you insert elements circullary, and remember where the first and the last elements are so you can add to beginning/end in O(1). Also when the array is full, you have to move all the elements to a larger one. If you double the size, you still get amortized time of O(1)
1) m_nextIn and m_nextOut - data attributes of class queue;
I find it useful to have two integers, with label m_nextIn and m_nextOut ... these identify where in the circular array you 'insert' the next (i.e. youngest) obj instance into the queue, and where you 'delete' the oldest obj instance from the queue.
These two items also provide constant time insert and delete.
Don't get confused as to where the beginning or end of the queue is. The array starts at index 0, but this is not the beginning of your queue.
The beginning of your queue is at nextIn (which probably is not 0, but may be). Technique also known as round-robin (a research term).
2) empty and full - method attributes
Determining queue full / empty can be easily computed from m_nextIn and m_nextOut.
3) extendable
Since you are prohibited from using vector (which itself is extendable) you must implement this functionality yourself.
Note about your comment: The "dynamic memory" concept is not related to stack. (another research term)
Extendable issues occur when your user code invokes the 'insert' AND the array is already full. (capture this test effort) You will need to detect this issue, then do 4 things:
3.1) allocate a new array (use new, and simply pick an appropriate size.)
Hint - std::vector() doubles it's capacity each time a push_back() would overflow the current capacity
3.2) transfer the entire contents of the array to the new array, fixing all the index's as you go. Since the new array is bigger, just insert trivially.
3.3) delete the old array - i.e. you copied from the old array to the new array, so do you 'delete' them? or simply delete the array?
3.4) finish the 'insert' - you were in the middle of inserting another instance, right?
Good luck.
What is the efficient way of implementing a queue, inorder to learn how it is implemented?
EDIT:
I looked into stl::queue code inorder to learn abt how it is implemented, but the template code making it difficult to understand. After all there is better efficient way is used than having a linked list.
The most efficent way is to have someone else do it.
Both C++ and C# (and .NET et al) have one in their native libraries.
Of course for any production code you should rely on a robust library implementation that's already withstood the test of time.
That said, for self-teaching it can be fun to write one yourself. I've done it before.
The most efficient way I know of is to use a similar approach to what most resizable collections do internally: store an array, which is increased in size (typically doubled) as needed when the collection's size reaches the length of the array.
A queue is a bit different from an ordinary collection, though, because you want to be able to pop off from the opposite end from where elements are pushed.
Obviously, to remove the first element and shift all other elements down one index would be costly and pointless. So instead you keep track of the starting and ending indices yourself. When the collection reaches the end of the array you use % to start pushing elements back at the beginning.
The key is simply working out your math so that you handle all cases, e.g., correctly growing the array when the queue is full, getting your bounds checks right, incrementing the start index (or looping back to 0) on every pop, etc.
Clearly, the design I've described above has many limitations: thread safety, for example. But for a simple, single-threaded, efficient implementation, it's a pretty good starting point.
Good luck -- and I also recommend posting your code if/when you've got one that you think is working!
If you can accept a maximum size for the queue, a circular buffer is super efficient. Because the library functions can't assume a maximum size they don't use this technique.
In the most generic sense, a linked-list would be your best bet if you maintain a front and rear pointer. In this case, queue insertion and deletion is an O(1) operation. You can also implement one using an array and maintaining indices for the front and rear. The math is marginally more involved (when you insert or delete you have to take into account "wrapping" to avoid going out of bounds).
For C++, stl::queue<>.
Do you understand how a queue works?
Do you understand how stl queue works?
Do you understand that "most efficient" is an abstract concept that can't hold true for every case?
If you get all of that, the "most efficient c++ queue algorithm" will come to you
If you need a thread-aware queue implementation you can try my own library. It's not complete yet, but it's well documented.
Edit: it's impemented by linked lists.
How many threads may be reading your queue at once? How many may be writing it at once? Can one thread be reading while another is writing? Do you want to pre-allocate space for the maximum size of queue? Do you need a way for a reader to block while waiting for data, or for a writer to block when the queue is full? How many objects per second do you expect to be feeding through the queue?
The optimal approach will depend upon the answers to those questions.
If your main goal is to learn how it is implemented, then you should work with linked lists. They are fun to work with and really shows the difference from sequential arrays and teaches a lot about memory.