如何使用两个堆栈实现队列?

时间:2008-09-16 03:37:34

标签: algorithm data-structures stack queue

假设我们有两个堆栈而没有其他临时变量。

是否可以仅使用两个堆栈“构造”队列数据结构?

21 个答案:

答案 0 :(得分:674)

保留2个筹码,我们称之为inboxoutbox

<强>入队

  • 将新元素推送到inbox

<强>出列

  • 如果outbox为空,请通过弹出inbox中的每个元素并将其推送到outbox

  • 来重新填充它
  • 弹出并返回outbox

  • 中的顶部元素

使用此方法,每个元素将在每个堆栈中恰好一次 - 意味着每个元素将被按两次并弹出两次,从而给出了分摊的常量时间操作。

这是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();
    }

}

答案 1 :(得分:197)

A - 如何反转堆栈

要了解如何使用两个堆栈构建队列,您应该了解如何反转堆栈清晰。记住堆栈是如何工作的,它非常类似于厨房的碟子堆栈。最后洗过的盘子将位于清洁堆栈的顶部,称为 L ast I n F irst O < / strong> ut(LIFO)计算机科学。

让我们想象我们的堆栈就像下面的瓶子一样;

enter image description here

如果我们分别推动整数1,2,3,那么3将位于堆栈的顶部。因为1将首先被推,然后2将被放在1的顶部。最后,3将被放在堆栈的顶部,我们的堆栈的最新状态表示为瓶子将如下;

enter image description here

现在我们将表示为瓶子的堆栈填充值3,2,1。我们想要反转堆栈,使堆栈的顶部元素为1,堆栈的底部元素为3.我们能做什么?我们可以拿起瓶子并将其倒置,以便所有值都按顺序反转?

enter image description here

是的,我们可以做到这一点,但那是一瓶。要执行相同的过程,我们需要有一个第二个堆栈,它将以相反的顺序存储第一个堆栈元素。让我们将填充的堆栈放在左边,将新的空堆栈放到右边。为了颠倒元素的顺序,我们将从左堆栈中弹出每个元素,并将它们推送到正确的堆栈。你可以看到我们在下面的图片中发生了什么;

enter image description here

所以我们知道如何反转堆栈。

B - 将两个堆栈用作队列

在上一部分中,我已经解释了如何反转堆栈元素的顺序。这很重要,因为如果我们将元素推送并弹出到堆栈,输出将完全按队列的相反顺序排列。考虑一个例子,让我们将整数数组{1, 2, 3, 4, 5}推送到一个堆栈。如果我们弹出元素并打印它们直到堆栈为空,我们将按推送顺序的相反顺序获取数组,这将是{5, 4, 3, 2, 1}请记住,对于相同的输入,如果我们将队列出列到队列为空,输出为{1, 2, 3, 4, 5}。因此很明显,对于元素的相同输入顺序,队列的输出正好与堆栈的输出相反。我们知道如何使用额外的堆栈来反转堆栈,我们可以使用两个堆栈构建一个队列。

我们的队列模型将包含两个堆栈。一个堆栈将用于enqueue操作(左侧的堆栈#1,将被称为输入堆栈),另一个堆栈将用于dequeue操作(右侧的堆栈#2,将被称为输出堆栈)。看看下面的图片;

enter image description here

我们的伪代码如下;

入队行动

Push every input element to the Input Stack

出列操作

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

让我们分别将整数{1, 2, 3}排入队列。整数将被推到位于左侧的输入堆栈堆栈#1 );

enter image description here

那么如果我们执行出队操作会发生什么?每当执行出队操作时,队列将检查输出堆栈是否为空(参见上面的伪代码)如果输出堆栈为空,则输出堆栈将在输出上被提取,因此元素输入堆栈将被反转。在返回值之前,队列的状态将如下所示;

enter image description here

检查输出堆栈(堆栈#2)中元素的顺序。很明显,我们可以从输出堆栈中弹出元素,这样输出就像我们从队列中出队一样。因此,如果我们执行两个出列操作,首先我们将分别获得{1, 2}。然后元素3将是输出堆栈的唯一元素,输入堆栈将为空。如果我们将元素4和5排入队列,那么队列的状态将如下;

enter image description here

现在输出堆栈不为空,如果我们执行出队操作,则只会从输出堆栈中弹出3。然后状态将如下所示;

enter image description here

同样,如果我们再执行两次出列操作,在第一次出列操作时,队列将检查输出堆栈是否为空,这是真的。然后弹出输入堆栈的元素并将它们推送到输出堆栈,输入堆栈为空,然后队列的状态如下;

enter image description here

很容易看出,两个出列操作的输出将是{4, 5}

C - 使用两个堆栈构建的队列的实现

这是Java中的一个实现。我不打算使用Stack的现有实现,所以这里的例子将重新发明轮子;

C - 1)MyStack类:简单堆栈实现

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类:使用两个堆栈的队列实现

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)演示代码

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)样本输出

Dequeued: 1
Dequeued: 2
Dequeued: 3
Dequeued: 4
Dequeued: 5

答案 2 :(得分:80)

您甚至可以仅使用一个堆栈来模拟队列。第二个(临时)堆栈可以通过对insert方法的递归调用的调用堆栈来模拟。

将新元素插入队列时,原则保持不变:

  • 您需要将元素从一个堆栈传输到另一个临时堆栈,以反转其顺序。
  • 然后将要插入的新元素推送到临时堆栈
  • 然后将元素转移回原始堆栈
  • 新元素将位于堆栈的底部,最旧的元素位于顶部(首先要弹出)

仅使用一个Stack的Queue类如下:

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();
    }
}

答案 3 :(得分:11)

但是,时间的复杂性会更糟。一个好的队列实现可以在不变的时间内完成所有工作。

修改

我不知道为什么我的答案在这里被低估了。如果我们编程,我们关心时间复杂度,并使用两个标准堆栈来制作队列是低效的。这是一个非常有效和相关的观点。如果其他人觉得需要更多地投票,我会很有兴趣知道原因。

更多详细信息:为什么使用两个堆栈比一个队列更糟糕:如果你使用两个堆栈,并且有人在发件箱为空时调用出队,你需要线性时间到达收件箱的底部(正如你在Dave的代码中看到的那样)。

您可以将队列实现为单链接列表(每个元素指向下一个插入的元素),保留指向最后插入元素的额外指针以进行推送(或使其成为循环列表)。在此数据结构上实现队列和出列很容易在恒定时间内完成。这是最坏情况下的常数时间,而非摊销。而且,由于评论似乎要求澄清,最坏情况下的常数时间绝对优于摊销的常数时间。

答案 4 :(得分:7)

让队列实现为q,用于实现q的栈是stack1和stack2。

q可以用两种方式实现:

方法1(通过使enQueue操作成本高昂)

此方法确保新输入的元素始终位于堆栈1的顶部,因此deQueue操作只是从stack1弹出。要将元素放在stack1的顶部,使用stack2。

enQueue(q, x)
1) While stack1 is not empty, push everything from stack1 to stack2.
2) Push x to stack1 (assuming size of stacks is unlimited).
3) Push everything back to stack1.
deQueue(q)
1) If stack1 is empty then error
2) Pop an item from stack1 and return it.

方法2(通过降低deQueue操作费用)

在此方法中,在队列操作中,新元素输入stack1的顶部。在去队列操作中,如果stack2为空,则将所有元素移动到stack2,最后返回stack2的顶部。

enQueue(q,  x)
 1) Push x to stack1 (assuming size of stacks is unlimited).

deQueue(q)
 1) If both stacks are empty then error.
 2) If stack2 is empty
   While stack1 is not empty, push everything from stack1 to stack2.
 3) Pop the element from stack2 and return it.

方法2肯定比​​方法1好。方法1在enQueue操作中移动所有元素两次,而方法2(在deQueue操作中)移动元素一次并仅在stack2为空时移动元素。

答案 5 :(得分:3)

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();
        }
}

答案 6 :(得分:2)

你必须从第一个堆栈中弹出所有东西以获得底部元素。然后将它们全部放回第二个堆栈以进行每次“出列”操作。

答案 7 :(得分:2)

对于c#developer来说,这是完整的程序:

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();
        }
    }
}

答案 8 :(得分:2)

队列中的两个堆栈定义为 stack1 stack2

<强>入队: 经过排除的元素总是被推入 stack1

<强>出列: 可以弹出 stack2 的顶部,因为它是 stack2 不为空时插入队列的第一个元素。当 stack2 为空时,我们会弹出 stack1 中的所有元素并将它们逐个推入 stack2 。队列中的第一个元素被推入 stack1 的底部。弹出和推送操作后,它可以直接弹出,因为它位于 stack2 的顶部。

以下是相同的C ++示例代码:

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;
}

此解决方案借鉴my blog。我的博客网页上提供了有关逐步操作模拟的更详细分析。

答案 9 :(得分:1)

// 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();

        }
    }

答案 10 :(得分:1)

在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()!)
            }
        }
    }
}

答案 11 :(得分:1)

虽然您将获得许多与实现具有两个堆栈的队列相关的帖子: 1.使enQueue过程成本更高 2.或者通过使deQueue过程更加昂贵

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

我从上面的帖子中发现的一个重要方法是构造只有堆栈数据结构和递归调用堆栈的队列。

虽然人们可以争辩说,这仍然使用两个堆栈,但理想情况下这只使用一个堆栈数据结构。

以下是问题的解释:

  1. 为enQueuing和deQueing数据声明一个堆栈并将数据推入堆栈。

  2. 而deQueueing有一个基本条件,当堆栈的大小为1时,堆栈的元素是poped。这将确保在deQueue递归期间没有堆栈溢出。

  3. deQueueing首先从堆栈顶部弹出数据。理想情况下,此元素将是存在于堆栈顶部的元素。现在一旦完成,递归调用deQueue函数,然后将弹出的元素推回到堆栈中。

  4. 代码如下所示:

    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;
    

    这样,您可以使用单个堆栈数据结构和递归调用堆栈创建队列。

答案 12 :(得分:1)

使用堆栈执行队列的以下操作。

push(x)-将元素x推到队列的后面。

pop()-从队列前面删除该元素。

peek()-获取前端元素。

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();
  }
}

答案 13 :(得分:0)

我会在Go中回答这个问题,因为Go在其标准库中没有丰富的集合。

由于堆栈实际上很容易实现,我想我会尝试使用两个堆栈来完成双端队列。为了更好地理解我是如何得出答案的,我将实现分为两部分,第一部分希望更容易理解,但它不完整。

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:]
    }
}

它基本上是两个堆栈,我们允许堆栈的底部彼此操纵。我还使用了STL命名约定,其中堆栈的传统push,pop,peek操作具有前/后前缀,无论它们是指队列的前面还是后面。

上述代码的问题在于它没有非常有效地使用内存。实际上,它会不断增长,直到你的空间不足为止。那太糟糕了。对此的修复是尽可能简单地重用堆栈空间的底部。我们必须引入一个偏移来跟踪这一点,因为Go中的切片一旦收缩就不能在前面生长。

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.")
        }
    }
}

它有很多小功能但是其中的6个功能中只有3个只是另一个的镜像。

答案 14 :(得分:0)

这是我在java中使用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;
    }
}

}

注意:在这种情况下,弹出操作非常耗时。所以我不建议使用两个堆栈创建队列。

答案 15 :(得分:0)

使用O(1) dequeue(),与pythonquick&#39; 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()

使用O(1) enqueue()(这篇文章中没有提到这个答案),它也使用回溯来冒泡并返回最底层的项目。

// 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

显然,这是一个很好的编码练习,因为它效率低但很优雅。

答案 16 :(得分:0)

以下是使用ES6语法的javascript语言解决方案。

Stack.js

Mongo CSharp Driver

QueueUsingTwoStacks.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 };

用法如下:

index.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 };

答案 17 :(得分:0)

**简易JS解决方案**

  • 注意:我从其他人的想法中提出了意见

/*

enQueue(q,  x)
 1) Push x to stack1 (assuming size of stacks is unlimited).

deQueue(q)
 1) If both stacks are empty then error.
 2) If stack2 is empty
   While stack1 is not empty, push everything from stack1 to stack2.
 3) Pop the element from stack2 and return it.

*/
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)

答案 18 :(得分:0)

我的 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;
        }
    }
?>

答案 19 :(得分:-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();
    }


}

对于每个排队操作,我们添加到stack1的顶部。对于每个dequeue,我们将stack1的内容清空到stack2中,并删除堆栈顶部的元素。时间复杂度为出队的O(n),因为我们必须将stack1复制到stack2。 enqueue的时间复杂度与常规堆栈相同

答案 20 :(得分:-2)

使用两个java.util.Stack对象实现队列:

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();
        }

}