462

Suppose we have two stacks and no other temporary variable.

Is to possible to "construct" a queue data structure using only the two stacks?

Levent Divilioglu
  • 11,198
  • 5
  • 59
  • 106
Nitin
  • 15,151
  • 8
  • 23
  • 14
  • For laughs, implement both stacks in a single array, one from each end growing towards each other. Compare the sequence of top-of stacks to a direct array implementation of queue. – greybeard Apr 22 '21 at 05:51

20 Answers20

795

Keep 2 stacks, let's call them inbox and outbox.

Enqueue:

  • Push the new element onto inbox

Dequeue:

  • If outbox is empty, refill it by popping each element from inbox and pushing it onto outbox

  • Pop and return the top element from outbox

Using this method, each element will be in each stack exactly once - meaning each element will be pushed twice and popped twice, giving amortized constant time operations.

Here's an implementation in Java:

public class Queue<E>
{

    private Stack<E> inbox = new Stack<E>();
    private Stack<E> outbox = new Stack<E>();

    public void queue(E item) {
        inbox.push(item);
    }

    public E dequeue() {
        if (outbox.isEmpty()) {
            while (!inbox.isEmpty()) {
               outbox.push(inbox.pop());
            }
        }
        return outbox.pop();
    }

}
rimsky
  • 1,163
  • 3
  • 16
  • 27
Dave L.
  • 43,907
  • 11
  • 63
  • 62
  • 21
    The worst-case time complexity is still O(n). I persist in saying this because I hope no students out there (this sounds like a homework/educational question) think this is an acceptable way to implement a queue. – Tyler Sep 16 '08 at 12:56
  • 44
    It is true that the worst-case time for a single pop operation is O(n) (where n is the current size of the queue). However, the worst-case time for a sequence of n queue operations is also O(n), giving us the amortized constant time. I wouldn't implement a queue this way, but it's not that bad. – Dave L. Sep 16 '08 at 14:06
  • Good point, but I wasn't trying to optimize as much as I was trying to write a solution that can be easily understood while answering the question " Is to possible". – Brian R. Bondy Sep 16 '08 at 15:48
  • If outbox is not empty, do you have to empty it out? Assuming we have new elements coming in all the time continuously? – Roozbeh15 Jan 15 '11 at 21:37
  • @Rooozbeh15 : No need to empty the outbox. The dequeue operation will take the element from the outbox only. The inbox is used for accomodating the incoming elements. – Flash Jan 16 '11 at 16:48
  • @Dave L.: I am a beginner in Computers. Can you explain how the worst-case time complexity for enqueue is O(n). I thought it to be O(1), constant time. This will be of great help to me. – smandape Sep 13 '11 at 15:12
  • For enqueue, it's always a single push operation, which should be O(1). It's a dequeue operation that can take O(n) in the worst case. – Dave L. Sep 15 '11 at 13:43
  • 1
    @Tyler If your stack is array based, as most are, you will always get O(n) worst case for a single operation. – Thomas Ahle Dec 06 '11 at 10:24
  • @ThomasAhle You can easily implement an O(1) worst-case stack with a linked list. I'm pretty sure this is how the C++ STL's stack is implemented. The deque is the default backing structure for an STL stack, and I think they use a linked list for deque, not an array. – Tyler Dec 28 '11 at 02:35
  • 2
    @Tyler: Check http://www.sgi.com/tech/stl/Deque.html . Deque "suports random access to elements" . Hence both deque and stack are array based. This is because it gives you better locality of reference and hence is faster in practice. – Thomas Ahle Dec 28 '11 at 10:21
  • 1
    @ThomasAhle Ok, I looked up the STL deque implementation, and it is a dynamically sized circular array. You get that point. But my main point still holds: stacks can be implemented with O(1) worst-case push/pop functions via linked list. O(1) worst-case is strictly better than O(1) amortized. There's no room for debate. If you want fast push/pops and nothing else, which is what a stack does, then there's no reason to forgo worst-case constant times. For the record, I was misled by this page's evidence that a deque has O(1) push/pop's: http://www.codeproject.com/KB/stl/vector_vs_deque.aspx – Tyler Dec 28 '11 at 21:26
  • 1
    @Tyler: I'm impressed with the speed of the deque in your referred study. However when methods have equal or nearly equal big-oh values as here, the only way to compare them is testing individual implementations. At least in java I found that LinkedList uses 3.75 times longer on appending on average, and 3.23 in median, than ArrayList. – Thomas Ahle Dec 30 '11 at 15:10
  • Originally posted as an answer by @Bajaj: There is a flaw in the solution suggested by Dave L. [http://stackoverflow.com/a/69436/1465918]. A deadlock scenario could occur or order of elements could fail during concurrent DeQueue and Enqueue operation. As each Dequeue involves popping from mainStack and pushing it into second Stack. and if new element added during this operation, the location of the new item might not retain last position – Devon_C_Miller Jun 19 '12 at 10:11
  • 1
    @Devon_C_Miller Indeed, the example in Java is not thread safe, just like most of the other collections in Java. As with any such class, if you want to use it in a multithreaded context, be sure to use synchronization or some other appropriate tool. – Dave L. Jun 20 '12 at 13:44
  • I'm confused by something. If I do this: a) queue 1,2,3 b) dequeue (returning 1). c) queue 4, 5 d) dequeue Then, I get back 4, not 2, which is what I would expect from a queue. Am I missing something? – Newtang Feb 24 '13 at 00:17
  • 16
    @Newtang a) queue 1,2,3 => **Inbox[3,2,1]/Outbox[]**. b) dequeue. outbox is empty, so refill => **Inbox[]/Outbox[1,2,3]**. Pop from outbox, return 1 => **Inbox[]/Outbox[2,3]**. c) queue 4,5 => **Inbox[5,4]/Outbox[2,3]**. d) dequeue. outbox is not empty, so pop from outbox, return 2 => **Inbox[5,4]/Outbox[3]**. Does that make more sense? – Dave L. Feb 25 '13 at 14:28
  • 2
    I remember this problem appeared in the book Crack the Coding Interview – spiralmoon Sep 11 '13 at 23:17
  • What happens if outbox is not empty ? – Binita Bharati Oct 21 '15 at 02:59
  • @BinitaBharati: Then a dequeue operation will simply pop the top item off outbox. – Dave L. Oct 21 '15 at 13:32
  • @DaveL. The complexity of the above approach for enqueue operation is O(1) and for for the dequeue is O(1) is there a way to reduce this complexity? I was asked this at an interview. – rd22 Mar 10 '17 at 16:00
  • @rd22 Actually, the worst case time complexity for dequeue is O(n), it's just the amortized time that is O(1). It's not possible to do better than this using only stacks. – Dave L. Mar 10 '17 at 20:38
  • @DaveL. Could you please help me understand how amortized constant time is O(1) ? i.e, one D-queue where current size is n would be O(n), hence continues n De-queues would be (n)+(n-1)+(n-2)+...+1 = n(n+1)/2 i.e, O(n^2) , Therefore I think amortized constant time is O(n) – Severus Tux Dec 12 '17 at 01:13
  • @SeverusTux The worst case for a single Dequeue is O(n), which is true. However, that only happens if there outbox is empty and there are O(n) items in the inbox. In that case, the total cost for each of the next set of operations is O(1) since they each only need to pop the top item off the outbox. So that gives O(n) + n * O(n) which equals O(n) + O(n) which is still just O(n). In other words, any time you have an expensive dequeue, it's guaranteed to be followed by many cheap dequeues, so it averages out fine. – Dave L. Dec 12 '17 at 04:16
  • 1
    Oh.. got it. Thanks. You mean O(n) + n * O( **1** ) i guess. – Severus Tux Dec 12 '17 at 07:25
  • Oops! Yes, that's what I meant. – Dave L. Dec 12 '17 at 16:08
  • @user355834 Need more specifics. A circular linked list is another structure that can efficiently implement the First In First Out semantics of a queue, but can also support other operations such as removing from the back of the queue. You could do other things with the stacks as well, but it really gets to the details of what operations you want to do and how efficient they are. Generally outside the scope of this exercise. – Dave L. Oct 28 '20 at 15:57
  • @User355834 I'd argue with the assertion that a circular linked list can be implemented via queue. A circular linked list is a structure with a set of nodes, each pointing to the next, and the last pointing back to the first. It can be used to implement a queue, but it doesn't really make sense to try to use a queue to implement a circular linked list. – Dave L. Oct 28 '20 at 21:06
309

A - How To Reverse A Stack

To understand how to construct a queue using two stacks, you should understand how to reverse a stack crystal clear. Remember how stack works, it is very similar to the dish stack on your kitchen. The last washed dish will be on the top of the clean stack, which is called as Last In First Out (LIFO) in computer science.

Lets imagine our stack like a bottle as below;

enter image description here

If we push integers 1,2,3 respectively, then 3 will be on the top of the stack. Because 1 will be pushed first, then 2 will be put on the top of 1. Lastly, 3 will be put on the top of the stack and latest state of our stack represented as a bottle will be as below;

enter image description here

Now we have our stack represented as a bottle is populated with values 3,2,1. And we want to reverse the stack so that the top element of the stack will be 1 and bottom element of the stack will be 3. What we can do ? We can take the bottle and hold it upside down so that all the values should reverse in order ?

enter image description here

Yes we can do that, but that's a bottle. To do the same process, we need to have a second stack that which is going to store the first stack elements in reverse order. Let's put our populated stack to the left and our new empty stack to the right. To reverse the order of the elements, we are going to pop each element from left stack, and push them to the right stack. You can see what happens as we do so on the image below;

enter image description here

So we know how to reverse a stack.

B - Using Two Stacks As A Queue

On previous part, I've explained how can we reverse the order of stack elements. This was important, because if we push and pop elements to the stack, the output will be exactly in reverse order of a queue. Thinking on an example, let's push the array of integers {1, 2, 3, 4, 5} to a stack. If we pop the elements and print them until the stack is empty, we will get the array in the reverse order of pushing order, which will be {5, 4, 3, 2, 1} Remember that for the same input, if we dequeue the queue until the queue is empty, the output will be {1, 2, 3, 4, 5}. So it is obvious that for the same input order of elements, output of the queue is exactly reverse of the output of a stack. As we know how to reverse a stack using an extra stack, we can construct a queue using two stacks.

Our queue model will consist of two stacks. One stack will be used for enqueue operation (stack #1 on the left, will be called as Input Stack), another stack will be used for the dequeue operation (stack #2 on the right, will be called as Output Stack). Check out the image below;

enter image description here

Our pseudo-code is as below;


Enqueue Operation

Push every input element to the Input Stack

Dequeue Operation

If ( Output Stack is Empty)
    pop every element in the Input Stack
    and push them to the Output Stack until Input Stack is Empty

pop from Output Stack

Let's enqueue the integers {1, 2, 3} respectively. Integers will be pushed on the Input Stack (Stack #1) which is located on the left;

enter image description here

Then what will happen if we execute a dequeue operation? Whenever a dequeue operation is executed, queue is going to check if the Output Stack is empty or not(see the pseudo-code above) If the Output Stack is empty, then the Input Stack is going to be extracted on the output so the elements of Input Stack will be reversed. Before returning a value, the state of the queue will be as below;

enter image description here

Check out the order of elements in the Output Stack (Stack #2). It's obvious that we can pop the elements from the Output Stack so that the output will be same as if we dequeued from a queue. Thus, if we execute two dequeue operations, first we will get {1, 2} respectively. Then element 3 will be the only element of the Output Stack, and the Input Stack will be empty. If we enqueue the elements 4 and 5, then the state of the queue will be as follows;

enter image description here

Now the Output Stack is not empty, and if we execute a dequeue operation, only 3 will be popped out from the Output Stack. Then the state will be seen as below;

enter image description here

Again, if we execute two more dequeue operations, on the first dequeue operation, queue will check if the Output Stack is empty, which is true. Then pop out the elements of the Input Stack and push them to the Output Stack unti the Input Stack is empty, then the state of the Queue will be as below;

enter image description here

Easy to see, the output of the two dequeue operations will be {4, 5}

C - Implementation Of Queue Constructed with Two Stacks

Here is an implementation in Java. I'm not going to use the existing implementation of Stack so the example here is going to reinvent the wheel;

C - 1) MyStack class : A Simple Stack Implementation

public class MyStack<T> {

    // inner generic Node class
    private class Node<T> {
        T data;
        Node<T> next;

        public Node(T data) {
            this.data = data;
        }
    }

    private Node<T> head;
    private int size;

    public void push(T e) {
        Node<T> newElem = new Node(e);

        if(head == null) {
            head = newElem;
        } else {
            newElem.next = head;
            head = newElem;     // new elem on the top of the stack
        }

        size++;
    }

    public T pop() {
        if(head == null)
            return null;

        T elem = head.data;
        head = head.next;   // top of the stack is head.next

        size--;

        return elem;
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public void printStack() {
        System.out.print("Stack: ");

        if(size == 0)
            System.out.print("Empty !");
        else
            for(Node<T> temp = head; temp != null; temp = temp.next)
                System.out.printf("%s ", temp.data);

        System.out.printf("\n");
    }
}

C - 2) MyQueue class : Queue Implementation Using Two Stacks

public class MyQueue<T> {

    private MyStack<T> inputStack;      // for enqueue
    private MyStack<T> outputStack;     // for dequeue
    private int size;

    public MyQueue() {
        inputStack = new MyStack<>();
        outputStack = new MyStack<>();
    }

    public void enqueue(T e) {
        inputStack.push(e);
        size++;
    }

    public T dequeue() {
        // fill out all the Input if output stack is empty
        if(outputStack.isEmpty())
            while(!inputStack.isEmpty())
                outputStack.push(inputStack.pop());

        T temp = null;
        if(!outputStack.isEmpty()) {
            temp = outputStack.pop();
            size--;
        }

        return temp;
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

}

C - 3) Demo Code

public class TestMyQueue {

    public static void main(String[] args) {
        MyQueue<Integer> queue = new MyQueue<>();

        // enqueue integers 1..3
        for(int i = 1; i <= 3; i++)
            queue.enqueue(i);

        // execute 2 dequeue operations 
        for(int i = 0; i < 2; i++)
            System.out.println("Dequeued: " + queue.dequeue());

        // enqueue integers 4..5
        for(int i = 4; i <= 5; i++)
            queue.enqueue(i);

        // dequeue the rest
        while(!queue.isEmpty())
            System.out.println("Dequeued: " + queue.dequeue());
    }

}

C - 4) Sample Output

Dequeued: 1
Dequeued: 2
Dequeued: 3
Dequeued: 4
Dequeued: 5
Levent Divilioglu
  • 11,198
  • 5
  • 59
  • 106
80

You can even simulate a queue using only one stack. The second (temporary) stack can be simulated by the call stack of recursive calls to the insert method.

The principle stays the same when inserting a new element into the queue:

  • You need to transfer elements from one stack to another temporary stack, to reverse their order.
  • Then push the new element to be inserted, onto the temporary stack
  • Then transfer the elements back to the original stack
  • The new element will be on the bottom of the stack, and the oldest element is on top (first to be popped)

A Queue class using only one Stack, would be as follows:

public class SimulatedQueue<E> {
    private java.util.Stack<E> stack = new java.util.Stack<E>();

    public void insert(E elem) {
        if (!stack.empty()) {
            E topElem = stack.pop();
            insert(elem);
            stack.push(topElem);
        }
        else
            stack.push(elem);
    }

    public E remove() {
        return stack.pop();
    }
}
pythonquick
  • 10,789
  • 6
  • 33
  • 28
  • 53
    Maybe the code looks elegant but it is very inefficient (O(n**2) insert) and it still has two stacks, one in the heap and one in the call stack, as @pythonquick points out. For a non-recursive algorithm, you can always grab one "extra" stack from the call stack in languages supporting recursion. – Antti Huima Apr 05 '11 at 17:59
  • 1
    @antti.huima And would you explain how this could be a quadratic insert?! From what I understand, insert does n pop and n push operations, so it's a perfectly linear O(n) algorithm. – Lionel Parreaux Jan 17 '14 at 11:56
  • 1
    @LP_ it takes quadratic time O(n^2) to insert `n items` in the queue using the above data structure. the sum `(1 + 2 + 4 + 8 + .... + 2(n-1))` results in `~O(n^2)`. I hope you get the point. – Ankit Kumar Mar 15 '14 at 04:14
  • 2
    @antti.huima You were talking about the complexity of the insert function (you said "O(n**2) insert" -- you probably meant "O(n**2) fill"). **By convention**, "the complexity insert" is the time _one_ insertion takes, which is here linear in the number of elements already present. If we talked in the time needed to insert _n_ items, we would say a hashtable has linear insert. Which is not the case. – Lionel Parreaux Mar 15 '14 at 11:15
  • 3
    You're essentially using the stack, as a stack. This means that if a large number of items are in the stack, you can end up with a stack overflow - it's almost like the solution was designed for this site! – UKMonkey Nov 25 '16 at 17:51
14

The time complexities would be worse, though. A good queue implementation does everything in constant time.

Edit

Not sure why my answer has been downvoted here. If we program, we care about time complexity, and using two standard stacks to make a queue is inefficient. It's a very valid and relevant point. If someone else feels the need to downvote this more, I would be interested to know why.

A little more detail: on why using two stacks is worse than just a queue: if you use two stacks, and someone calls dequeue while the outbox is empty, you need linear time to get to the bottom of the inbox (as you can see in Dave's code).

You can implement a queue as a singly-linked list (each element points to the next-inserted element), keeping an extra pointer to the last-inserted element for pushes (or making it a cyclic list). Implementing queue and dequeue on this data structure is very easy to do in constant time. That's worst-case constant time, not amortized. And, as the comments seem to ask for this clarification, worst-case constant time is strictly better than amortized constant time.

Tyler
  • 28,498
  • 11
  • 90
  • 106
  • 1
    Not in the average case. Brian's answer describes a queue which would have amortized constant enqueue *and* dequeue operations. – Daniel Spiewak Sep 16 '08 at 03:53
  • That's true. You have average case & amortized time complexity the same. But the default is usually worst-case per-operation, and this is O(n) where n is the current size of the structure. – Tyler Sep 16 '08 at 04:51
  • 1
    Worst case can also be amortized. For example, mutable dynamic arrays (vectors) are usually considered to have constant insertion time, even though an expensive resize-and-copy operation is required every so often. – Daniel Spiewak Sep 16 '08 at 08:33
  • 1
    "Worst-case" and "amortized" are two different types of time complexity. It doesn't make sense to say that "worst-case can be amortized" -- if you could make the worst-case = the amortized, then this would be a significant improvement; you would just talk about worst-case, with no averaging. – Tyler Sep 16 '08 at 12:51
  • I'm not sure what you mean by O(1) worst-case being "strictly better" than a combination of O(1) average case and O(n) worst-case. Constant scaling factors matter. A data structure which, if it contains N items, may need to be repacked after N operations at a time of N microseconds, and otherwise takes one microsecond per operation, may be far more useful than one which takes a millisecond for each operation, even if the data size will expand to millions of items (thus implying that some individual operations would take multiple seconds). – supercat Sep 25 '12 at 22:04
  • @supercat, you're right that some algorithms may have a slower time complexity yet may be faster for small-sized inputs. My statement was about worst-case vs amortized time complexity in general. If all you know is that one alg is O(f(n)) worst-case and the other is O(f(n)) amortized, then the worst-case analysis gives you more information. This is relevant to queues. Suppose you're writing a realtime video game, where a constant 1ms per queue-op is ok, but even an occasional slow queue-op will appear as lag to the user. Then you care about worst-case performance, and this is just one example. – Tyler Sep 26 '12 at 01:44
  • @Tyler: My point wasn't about small-size inputs. My point was about big batches of inputs. A typical amortized-constant-time algorithms will be able to guarantee that the total cost to perform M consecutive operations on a data set of size N will be O(M)+O(N). If N is O(M) [meaning the number of operations to be performed is at least a constant fraction of the data set size], then O(M)+O(N) will be O(M). The fact that some individual operations may take time O(N) won't adversely affect the time to perform M of them. In practical terms... – supercat Sep 26 '12 at 15:20
  • ...it's often possible for amortized-time algorithms to guarantee that provided one performs some number operations on a data set of a particular size (the number depending upon the size), the time saved on the operations which are processed quickly will outweigh the extra time taken by those which do not. If one doesn't care about the time required to process individual operations, but only groups which are larger than that size, the amortized-time operation may be strictly better. – supercat Sep 26 '12 at 15:22
  • @Tyler: why is your proposal the worst-case constant time, not normal time? – ying May 20 '13 at 20:02
  • @supercat: can you elaborate more why 2-stack approach is better than Tyler's approach? – ying May 20 '13 at 20:05
  • @ying: Forward-linked-list queues can be useful in some scenarios, but Tyler's answer seemed to derisively suggest that one should without exception always judge algorithms by their worst-case performance. In many cases, double-stack queues may be just as good as anything else from a performance standpoint, especially if what one cares about is the total time an application spends putting objects into a queue and taking them out. – supercat May 20 '13 at 20:47
  • @supercat: I understand the point about worst time vs avg time. But my understanding is double-stack queue need to copy/move element between stacks to achieve FIFO while linked list doesn't need copying at all and is much simpler. So what's the gain for double-stack queue? Some ppl (http://stackoverflow.com/a/8357639/1294552) mentioned immutability and thread-safe, but linked list can also achieve it. Can you explain under what condition to choose double-stack queue rather than linkedlist queue? How to choose? Thanks. – ying May 20 '13 at 22:42
  • @ying: Adding an item to a lock-free stack is simple: `do {newItem.next = firstLink;} while CompareExchange(firstLink, newItem, newItem.next);` The amount of contention in multi-processor scenarios is a function of the amount of code within the `CompareExchange` loop. All lock-free linked-list approaches I know of have more complicated producer loop. Further, if one looks at the total amount of work that will have to be done on each item in the two-stack approach, from the time it enters to the time it leaves, it's pretty small. – supercat May 20 '13 at 23:55
  • @supercat: This question seems helpful: http://stackoverflow.com/questions/2050120/why-use-two-stacks-to-make-a-queue – ying May 21 '13 at 02:13
  • @supercat: how to impl lock free atomic copying elements from one stack to the other? – ying May 21 '13 at 14:50
  • @ying: Note that in common implementations of the two-stack approach, each stack *is* a linked list; the difference is that when the list on on the "add items" side each links points to the previous item rather than the next. When the reader's stack gets try and it has to grab the writer's stack, the reversal can be done in place with a simple loop. The behavior is equivalent to popping all items off one stack and pushing on the other, but the implementation can be much faster. In some cases, building the queue with forward-pointers may have an advantage... – supercat May 21 '13 at 14:58
  • @ying: ...in that each item will have to be accessed twice in rapid succession (when writing it, and when writing the next item) and then once much later (when reading), while in a double-stack queue the three accesses would be more disjoint in time; thus, the latter approach may have three cache misses in cases where the former would only have two. Note that the reversal need not be atomic in the many-writers one-reader case, since the reversal would be done by the (only) reader thread. – supercat May 21 '13 at 15:01
5

Implement the following operations of a queue using stacks.

push(x) -- Push element x to the back of queue.

pop() -- Removes the element from in front of queue.

peek() -- Get the front element.

empty() -- Return whether the queue is empty.

enter image description here

class MyQueue {

  Stack<Integer> input;
  Stack<Integer> output;

  /** Initialize your data structure here. */
  public MyQueue() {
    input = new Stack<Integer>();
    output = new Stack<Integer>();
  }

  /** Push element x to the back of queue. */
  public void push(int x) {
    input.push(x);
  }

  /** Removes the element from in front of queue and returns that element. */
  public int pop() {
    peek();
    return output.pop();
  }

  /** Get the front element. */
  public int peek() {
    if(output.isEmpty()) {
        while(!input.isEmpty()) {
            output.push(input.pop());
        }
    }
    return output.peek();
  }

  /** Returns whether the queue is empty. */
  public boolean empty() {
    return input.isEmpty() && output.isEmpty();
  }
}
Girish Rathi
  • 129
  • 1
  • 4
4

A solution in c#

public class Queue<T> where T : class
{
    private Stack<T> input = new Stack<T>();
    private Stack<T> output = new Stack<T>();
    public void Enqueue(T t)
    {
        input.Push(t);
    }

    public T Dequeue()
    {
        if (output.Count == 0)
        {
            while (input.Count != 0)
            {
                output.Push(input.Pop());
            }
        }

        return output.Pop();
    }
}
Hammad Sajid
  • 312
  • 1
  • 3
  • 14
Santhosh
  • 729
  • 7
  • 19
2

Two stacks in the queue are defined as stack1 and stack2.

Enqueue: The euqueued elements are always pushed into stack1

Dequeue: The top of stack2 can be popped out since it is the first element inserted into queue when stack2 is not empty. When stack2 is empty, we pop all elements from stack1 and push them into stack2 one by one. The first element in a queue is pushed into the bottom of stack1. It can be popped out directly after popping and pushing operations since it is on the top of stack2.

The following is same C++ sample code:

template <typename T> class CQueue
{
public:
    CQueue(void);
    ~CQueue(void);

    void appendTail(const T& node); 
    T deleteHead();                 

private:
    stack<T> stack1;
    stack<T> stack2;
};

template<typename T> void CQueue<T>::appendTail(const T& element) {
    stack1.push(element);
} 

template<typename T> T CQueue<T>::deleteHead() {
    if(stack2.size()<= 0) {
        while(stack1.size()>0) {
            T& data = stack1.top();
            stack1.pop();
            stack2.push(data);
        }
    }


    if(stack2.size() == 0)
        throw new exception("queue is empty");


    T head = stack2.top();
    stack2.pop();


    return head;
}

This solution is borrowed from my blog. More detailed analysis with step-by-step operation simulations is available in my blog webpage.

Andrew Barber
  • 39,603
  • 20
  • 94
  • 123
Harry He
  • 1,795
  • 16
  • 12
2

for c# developer here is the complete program :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace QueueImplimentationUsingStack
{
    class Program
    {
        public class Stack<T>
        {
            public int size;
            public Node<T> head;
            public void Push(T data)
            {
                Node<T> node = new Node<T>();
                node.data = data;
                if (head == null)
                    head = node;
                else
                {
                    node.link = head;
                    head = node;
                }
                size++;
                Display();
            }
            public Node<T> Pop()
            {
                if (head == null)
                    return null;
                else
                {
                    Node<T> temp = head;
                    //temp.link = null;
                    head = head.link;
                    size--;
                    Display();
                    return temp;
                }
            }
            public void Display()
            {
                if (size == 0)
                    Console.WriteLine("Empty");
                else
                {
                    Console.Clear();
                    Node<T> temp = head;
                    while (temp!= null)
                    {
                        Console.WriteLine(temp.data);
                        temp = temp.link;
                    }
                }
            }
        }

        public class Queue<T>
        {
            public int size;
            public Stack<T> inbox;
            public Stack<T> outbox;
            public Queue()
            {
                inbox = new Stack<T>();
                outbox = new Stack<T>();
            }
            public void EnQueue(T data)
            {
                inbox.Push(data);
                size++;
            }
            public Node<T> DeQueue()
            {
                if (outbox.size == 0)
                {
                    while (inbox.size != 0)
                    {
                        outbox.Push(inbox.Pop().data);
                    }
                }
                Node<T> temp = new Node<T>();
                if (outbox.size != 0)
                {
                    temp = outbox.Pop();
                    size--;
                }
                return temp;
            }

        }
        public class Node<T>
        {
            public T data;
            public Node<T> link;
        }

        static void Main(string[] args)
        {
            Queue<int> q = new Queue<int>();
            for (int i = 1; i <= 3; i++)
                q.EnQueue(i);
           // q.Display();
            for (int i = 1; i < 3; i++)
                q.DeQueue();
            //q.Display();
            Console.ReadKey();
        }
    }
}
Jaydeep Shil
  • 1,894
  • 22
  • 21
2

You'll have to pop everything off the first stack to get the bottom element. Then put them all back onto the second stack for every "dequeue" operation.

Witold Kaczurba
  • 9,845
  • 3
  • 58
  • 67
user11055
  • 208
  • 2
  • 3
1

An implementation of a queue using two stacks in Swift:

struct Stack<Element> {
    var items = [Element]()

    var count : Int {
        return items.count
    }

    mutating func push(_ item: Element) {
        items.append(item)
    }

    mutating func pop() -> Element? {
        return items.removeLast()
    }

    func peek() -> Element? {
        return items.last
    }
}

struct Queue<Element> {
    var inStack = Stack<Element>()
    var outStack = Stack<Element>()

    mutating func enqueue(_ item: Element) {
        inStack.push(item)
    }

    mutating func dequeue() -> Element? {
        fillOutStack() 
        return outStack.pop()
    }

    mutating func peek() -> Element? {
        fillOutStack()
        return outStack.peek()
    }

    private mutating func fillOutStack() {
        if outStack.count == 0 {
            while inStack.count != 0 {
                outStack.push(inStack.pop()!)
            }
        }
    }
}
davejlin
  • 903
  • 9
  • 18
1

While you will get a lot of posts related to implementing a queue with two stacks : 1. Either by making the enQueue process a lot more costly 2. Or by making the deQueue process a lot more costly

https://www.geeksforgeeks.org/queue-using-stacks/

One important way I found out from the above post was constructing queue with only stack data structure and the recursion call stack.

While one can argue that literally this is still using two stacks, but then ideally this is using only one stack data structure.

Below is the explanation of the problem:

  1. Declare a single stack for enQueuing and deQueing the data and push the data into the stack.

  2. while deQueueing have a base condition where the element of the stack is poped when the size of the stack is 1. This will ensure that there is no stack overflow during the deQueue recursion.

  3. While deQueueing first pop the data from the top of the stack. Ideally this element will be the element which is present at the top of the stack. Now once this is done, recursively call the deQueue function and then push the element popped above back into the stack.

The code will look like below:

if (s1.isEmpty())
System.out.println("The Queue is empty");
        else if (s1.size() == 1)
            return s1.pop();
        else {
            int x = s1.pop();
            int result = deQueue();
            s1.push(x);
            return result;

This way you can create a queue using a single stack data structure and the recursion call stack.

Radioactive
  • 611
  • 1
  • 11
  • 20
  • `Below is the explanation of the problem` promises, promises - `1.`, `2.`, and `3.` look a stab at describing a *solution*. Why `s1` when there is neither `s0` nor `s2`? There is an `else` following a `return`. There is an opening `{` with no matching `}`. – greybeard Apr 22 '21 at 06:28
1

Below is the solution in javascript language using ES6 syntax.

Stack.js

//stack using array
class Stack {
  constructor() {
    this.data = [];
  }

  push(data) {
    this.data.push(data);
  }

  pop() {
    return this.data.pop();
  }

  peek() {
    return this.data[this.data.length - 1];
  }

  size(){
    return this.data.length;
  }
}

export { Stack };

QueueUsingTwoStacks.js

import { Stack } from "./Stack";

class QueueUsingTwoStacks {
  constructor() {
    this.stack1 = new Stack();
    this.stack2 = new Stack();
  }

  enqueue(data) {
    this.stack1.push(data);
  }

  dequeue() {
    //if both stacks are empty, return undefined
    if (this.stack1.size() === 0 && this.stack2.size() === 0)
      return undefined;

    //if stack2 is empty, pop all elements from stack1 to stack2 till stack1 is empty
    if (this.stack2.size() === 0) {
      while (this.stack1.size() !== 0) {
        this.stack2.push(this.stack1.pop());
      }
    }

    //pop and return the element from stack 2
    return this.stack2.pop();
  }
}

export { QueueUsingTwoStacks };

Below is the usage:

index.js

import { StackUsingTwoQueues } from './StackUsingTwoQueues';

let que = new QueueUsingTwoStacks();
que.enqueue("A");
que.enqueue("B");
que.enqueue("C");

console.log(que.dequeue());  //output: "A"
Jyoti Prasad Pal
  • 1,569
  • 3
  • 26
  • 41
  • 1
    This is bugged. If you enqueue more elements after dequeueing, you'll put them in `stack1`. When you go to `dequeue` again, you'll move them items into `stack2`, putting them ahead of what was already there. – Alexander Apr 29 '19 at 17:26
  • @Alexander: `you'll move them items into stack2, putting them ahead of what was already there` if and only if `this.stack2.size() === 0`, putting those elements before - *nothing*. – greybeard Apr 22 '21 at 06:22
  • 1
    Haha I wrote that 3 years ago (almost to the date), and now I can't understand what I meant – Alexander Apr 22 '21 at 13:44
1

**Easy JS solution **

  • Note: I took ideas from other people comment

class myQueue {
    constructor() {
        this.stack1 = [];
        this.stack2 = [];
    }

    push(item) {
        this.stack1.push(item)
    }

    remove() {
        if (this.stack1.length == 0 && this.stack2.length == 0) {
            return "Stack are empty"
        }

        if (this.stack2.length == 0) {

            while (this.stack1.length != 0) {
                this.stack2.push(this.stack1.pop())
            }
        }
        return this.stack2.pop()
    }


    peek() {
        if (this.stack2.length == 0 && this.stack1.length == 0) {
            return 'Empty list'
        }

        if (this.stack2.length == 0) {
            while (this.stack1.length != 0) {
                this.stack2.push(this.stack1.pop())
            }
        }

        return this.stack2[0]
    }

    isEmpty() {
        return this.stack2.length === 0 && this.stack1.length === 0;
    }

}

const q = new myQueue();
q.push(1);
q.push(2);
q.push(3);
q.remove()

console.log(q)
blackgreen
  • 34,072
  • 23
  • 111
  • 129
ASHISH R
  • 4,043
  • 1
  • 20
  • 16
0
// Two stacks s1 Original and s2 as Temp one
    private Stack<Integer> s1 = new Stack<Integer>();
    private Stack<Integer> s2 = new Stack<Integer>();

    /*
     * Here we insert the data into the stack and if data all ready exist on
     * stack than we copy the entire stack s1 to s2 recursively and push the new
     * element data onto s1 and than again recursively call the s2 to pop on s1.
     * 
     * Note here we can use either way ie We can keep pushing on s1 and than
     * while popping we can remove the first element from s2 by copying
     * recursively the data and removing the first index element.
     */
    public void insert( int data )
    {
        if( s1.size() == 0 )
        {
            s1.push( data );
        }
        else
        {
            while( !s1.isEmpty() )
            {
                s2.push( s1.pop() );
            }
            s1.push( data );
            while( !s2.isEmpty() )
            {
                s1.push( s2.pop() );
            }
        }
    }

    public void remove()
    {
        if( s1.isEmpty() )
        {
            System.out.println( "Empty" );
        }
        else
        {
            s1.pop();

        }
    }
imvp
  • 123
  • 1
  • 11
0

I'll answer this question in Go because Go does not have a rich a lot of collections in its standard library.

Since a stack is really easy to implement I thought I'd try and use two stacks to accomplish a double ended queue. To better understand how I arrived at my answer I've split the implementation in two parts, the first part is hopefully easier to understand but it's incomplete.

type IntQueue struct {
    front       []int
    back        []int
}

func (q *IntQueue) PushFront(v int) {
    q.front = append(q.front, v)
}

func (q *IntQueue) Front() int {
    if len(q.front) > 0 {
        return q.front[len(q.front)-1]
    } else {
        return q.back[0]
    }
}

func (q *IntQueue) PopFront() {
    if len(q.front) > 0 {
        q.front = q.front[:len(q.front)-1]
    } else {
        q.back = q.back[1:]
    }
}

func (q *IntQueue) PushBack(v int) {
    q.back = append(q.back, v)
}

func (q *IntQueue) Back() int {
    if len(q.back) > 0 {
        return q.back[len(q.back)-1]
    } else {
        return q.front[0]
    }
}

func (q *IntQueue) PopBack() {
    if len(q.back) > 0 {
        q.back = q.back[:len(q.back)-1]
    } else {
        q.front = q.front[1:]
    }
}

It's basically two stacks where we allow the bottom of the stacks to be manipulated by each other. I've also used the STL naming conventions, where the traditional push, pop, peek operations of a stack have a front/back prefix whether they refer to the front or back of the queue.

The issue with the above code is that it doesn't use memory very efficiently. Actually, it grows endlessly until you run out of space. That's really bad. The fix for this is to simply reuse the bottom of the stack space whenever possible. We have to introduce an offset to track this since a slice in Go cannot grow in the front once shrunk.

type IntQueue struct {
    front       []int
    frontOffset int
    back        []int
    backOffset  int
}

func (q *IntQueue) PushFront(v int) {
    if q.backOffset > 0 {
        i := q.backOffset - 1
        q.back[i] = v
        q.backOffset = i
    } else {
        q.front = append(q.front, v)
    }
}

func (q *IntQueue) Front() int {
    if len(q.front) > 0 {
        return q.front[len(q.front)-1]
    } else {
        return q.back[q.backOffset]
    }
}

func (q *IntQueue) PopFront() {
    if len(q.front) > 0 {
        q.front = q.front[:len(q.front)-1]
    } else {
        if len(q.back) > 0 {
            q.backOffset++
        } else {
            panic("Cannot pop front of empty queue.")
        }
    }
}

func (q *IntQueue) PushBack(v int) {
    if q.frontOffset > 0 {
        i := q.frontOffset - 1
        q.front[i] = v
        q.frontOffset = i
    } else {
        q.back = append(q.back, v)
    }
}

func (q *IntQueue) Back() int {
    if len(q.back) > 0 {
        return q.back[len(q.back)-1]
    } else {
        return q.front[q.frontOffset]
    }
}

func (q *IntQueue) PopBack() {
    if len(q.back) > 0 {
        q.back = q.back[:len(q.back)-1]
    } else {
        if len(q.front) > 0 {
            q.frontOffset++
        } else {
            panic("Cannot pop back of empty queue.")
        }
    }
}

It's a lot of small functions but of the 6 functions 3 of them are just mirrors of the other.

John Leidegren
  • 59,920
  • 20
  • 131
  • 152
  • You're using arrays here. I don't see where your stacks are. – melpomene Aug 06 '16 at 08:55
  • @melpomene OK, if you take a closer look you'll notice that the only operations that I'm performing is adding/removing of the last element in the array. In other words, pushing and popping. For all intent and purposes these are stacks but implemented using arrays. – John Leidegren Aug 06 '16 at 10:22
  • @melpomene Actually, that's only half right, I am assuming doubled ended stacks. I am allowing the stack to be modified in a non standard way from bottom up under certain conditions. – John Leidegren Aug 06 '16 at 10:24
0

With O(1) dequeue(), which is same as pythonquick's answer:

// time: O(n), space: O(n)
enqueue(x):
    if stack.isEmpty():
        stack.push(x)
        return
    temp = stack.pop()
    enqueue(x)
    stack.push(temp)

// time: O(1)
x dequeue():
    return stack.pop()

With O(1) enqueue() (this is not mentioned in this post so this answer), which also uses backtracking to bubble up and return the bottommost item.

// O(1)
enqueue(x):
    stack.push(x)

// time: O(n), space: O(n)
x dequeue():
    temp = stack.pop()
    if stack.isEmpty():
        x = temp
    else:
        x = dequeue()
        stack.push(temp)
    return x

Obviously, it's a good coding exercise as it inefficient but elegant nevertheless.

hIpPy
  • 4,649
  • 6
  • 51
  • 65
0

My Solution with PHP

<?php
$_fp = fopen("php://stdin", "r");
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
    $queue = array();
    $count = 0;
    while($line = fgets($_fp)) {
        if($count == 0) {
            $noOfElement = $line;
            $count++;
            continue;
        }
        $action = explode(" ",$line);
        $case = $action[0];
        switch($case) {
            case 1:
                $enqueueValue = $action[1];
                array_push($queue, $enqueueValue);
                break;
            case 2:
                array_shift($queue);
                break;
            case 3:
                $show = reset($queue);
                print_r($show);
                break;
            default:
                break;
        }
    }
?>
Sarang
  • 754
  • 3
  • 9
  • 24
-1
public class QueueUsingStacks<T>
{
    private LinkedListStack<T> stack1;
    private LinkedListStack<T> stack2;

    public QueueUsingStacks()
    {
        stack1=new LinkedListStack<T>();
        stack2 = new LinkedListStack<T>();

    }
    public void Copy(LinkedListStack<T> source,LinkedListStack<T> dest )
    {
        while(source.Head!=null)
        {
            dest.Push(source.Head.Data);
            source.Head = source.Head.Next;
        }
    }
    public void Enqueue(T entry)
    {

       stack1.Push(entry);
    }
    public T Dequeue()
    {
        T obj;
        if (stack2 != null)
        {
            Copy(stack1, stack2);
             obj = stack2.Pop();
            Copy(stack2, stack1);
        }
        else
        {
            throw new Exception("Stack is empty");
        }
        return obj;
    }

    public void Display()
    {
        stack1.Display();
    }


}

For every enqueue operation, we add to the top of the stack1. For every dequeue, we empty the content's of stack1 into stack2, and remove the element at top of the stack.Time complexity is O(n) for dequeue, as we have to copy the stack1 to stack2. time complexity of enqueue is the same as a regular stack

Matthias
  • 7,432
  • 6
  • 55
  • 88
PradGar
  • 103
  • 1
  • 4
  • This code is inefficient (unnecessary copying) and broken: `if (stack2 != null)` is always true because `stack2` is instantiated in the constructor. – melpomene Aug 06 '16 at 08:56
-1

here is my solution in Java using linkedlist.

class queue<T>{
    static class Node<T>{
        private T data;
        private Node<T> next;
        Node(T data){
            this.data = data;
            next = null;
        }
    }
    Node firstTop;
    Node secondTop;
    
    void push(T data){
        Node temp = new Node(data);
        temp.next = firstTop;
        firstTop = temp;
    }
    
    void pop(){
        if(firstTop == null){
            return;
        }
        Node temp = firstTop;
        while(temp != null){
            Node temp1 = new Node(temp.data);
            temp1.next = secondTop;
            secondTop = temp1;
            temp = temp.next;
        }
        secondTop = secondTop.next;
        firstTop = null;
        while(secondTop != null){
            Node temp3 = new Node(secondTop.data);
            temp3.next = firstTop;
            firstTop = temp3;
            secondTop = secondTop.next;
        }
    }
    
}

Note: In this case, pop operation is very time consuming. So I won't suggest to create a queue using two stacks.

greybeard
  • 2,249
  • 8
  • 30
  • 66
Irshad ck
  • 90
  • 2
  • Where are the *queue operations*, say, `enqueue(T value)` and `T dequeue()`? Is it necessary to instantiate `Node`s in `pop()`? Without a description of the number of operations necessary, this answer is not useful. – greybeard Apr 22 '21 at 06:19
-2

Queue implementation using two java.util.Stack objects:

public final class QueueUsingStacks<E> {

        private final Stack<E> iStack = new Stack<>();
        private final Stack<E> oStack = new Stack<>();

        public void enqueue(E e) {
            iStack.push(e);
        }

        public E dequeue() {
            if (oStack.isEmpty()) {
                if (iStack.isEmpty()) {
                    throw new NoSuchElementException("No elements present in Queue");
                }
                while (!iStack.isEmpty()) {
                    oStack.push(iStack.pop());
                }
            }
            return oStack.pop();
        }

        public boolean isEmpty() {
            if (oStack.isEmpty() && iStack.isEmpty()) {
                return true;
            }
            return false;
        }

        public int size() {
            return iStack.size() + oStack.size();
        }

}
realPK
  • 2,630
  • 29
  • 22
  • 3
    This code is functionally identical to the answer by Dave L. It adds nothing new, not even an explanation. – melpomene Aug 06 '16 at 08:59
  • It adds isEmpty() and size() methods along with basic exception handling. I will edit to add explanation. – realPK Aug 06 '16 at 15:23
  • 1
    No one asked for those extra methods, and they're trivial (one line each): `return inbox.isEmpty() && outbox.isEmpty()` and `return inbox.size() + outbox.size()`, respectively. Dave L.'s code already throws an exception when you dequeue from an empty queue. The original question wasn't even about Java; it was about data structures / algorithms in general. The Java implementation was just an additional illustration. – melpomene Aug 06 '16 at 17:07
  • 1
    This is a great source for people looking to understand how to build queue from two stacks, the diagrams most definitely helped me more than reading Dave's answer. – Kemal Tezer Dilsiz Oct 03 '16 at 05:34
  • @melpomene: Its not about methods being trivial but of need. Queue interface in Java extends those methods from Collection interface because they are needed. – realPK Mar 04 '17 at 23:37
  • 1
    @KemalTezerDilsiz What diagrams? Did you comment on the wrong answer? – melpomene Mar 04 '17 at 23:45