使用两个队列实现堆栈

Posted

技术标签:

【中文标题】使用两个队列实现堆栈【英文标题】:Implement Stack using Two Queues 【发布时间】:2010-10-15 20:30:15 【问题描述】:

之前there 提出了类似的问题,但这里的问题是相反的,使用两个队列作为堆栈。问题...

给定两个具有标准操作的队列(enqueuedequeueisemptysize),使用其标准操作(poppushisempty、@987654338)实现一个堆栈@)。

解决方案应该有两个版本。

版本A:推送项目时堆栈应该是有效的;和 版本 B:堆栈在弹出项目时应该是有效的。

比起任何特定的语言实现,我对算法更感兴趣。但是,我欢迎使用我熟悉的语言表达的解决方案 (java,c#,python,vb,javascript,php)。

【问题讨论】:

没错! CLRS - 10.1-6 (tinyurl.com/clrs-ex-10-1-6) One Stack, Two Queues 提供了一个优雅的解决方案,其中Pop 在 $O(1)$ 中工作,Push 在 $O(\sqrtn)$ 摊销时间内工作。 @rampion 现在它的 CLRS - 10.1-7。 :) 相关帖子。这是使用only一个队列here实现堆栈的另一个有趣问题。 【参考方案1】:

一种易于理解和实施的不同方法可能是:

    添加操作 --> 始终在空队列中添加元素,并在添加该元素后将所有其他元素从其他非空队列移动到此队列。 Pop 操作 --> 无论哪个队列不为空,对其执行删除/轮询并返回。 顶部操作 --> 无论哪个队列不为空,对其执行 peek 并返回。 打印 --> 无论哪个队列不为空,打印它。

【讨论】:

【参考方案2】:
import java.util.Deque;
import java.util.LinkedList;
import java.util.Queue;

public class ImplementationOfStackUsingTwoQueue 

    private static Deque<Integer> inboxQueue = new LinkedList<>();
    private static Queue<Integer> outboxQueue = new LinkedList<>();
    
    public void pushInStack(Integer val)
        inboxQueue.add(val);
    
    
    public void popFromStack()
        
        if(outboxQueue.isEmpty())
            while(!inboxQueue.isEmpty())
                outboxQueue.add(inboxQueue.pollLast());
            
        
    
    
    public static void main(String[] args) 
        
        ImplementationOfStackUsingTwoQueue obj = new ImplementationOfStackUsingTwoQueue();
        
        obj.pushInStack(1);
        obj.pushInStack(2);
        obj.pushInStack(3);
        obj.pushInStack(4);
        obj.pushInStack(5);
        System.out.println("After pushing the values in Queue" + inboxQueue);
        
        obj.popFromStack();
        System.out.println("After popping the values from Queue" + outboxQueue);    
    

【讨论】:

请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助、质量更好,并且更有可能吸引投票【参考方案3】:
template <typename T>
class stackfmtoq 
    queue<T> q1;
    queue<T> q2;
public:
    void push(T data) 
        while (!q2.empty()) 
            q1.push(q2.front());
            q2.pop();
        
        q2.push(data);
        while (!q1.empty()) 
            q2.push(q1.front());
            q1.pop();
        
    
    T pop() 
        if (q2.empty()) 
            cout << "Stack is Empty\n";
            return NULL;
        
        T ret = q2.front();
        q2.pop();
        return ret;
    
    T top() 
        if (q2.empty()) return NULL;
        return q2.front();
    
;

【讨论】:

【参考方案4】:

C#中的高效解决方案

public class MyStack 
    private Queue<int> q1 = new Queue<int>();
    private Queue<int> q2 = new Queue<int>();
    private int count = 0;

    /**
     * Initialize your data structure here.
     */
    public MyStack() 
    

    /**
     * Push element x onto stack.
     */
    public void Push(int x) 
        count++;
        q1.Enqueue(x);
        while (q2.Count > 0) 
            q1.Enqueue(q2.Peek());
            q2.Dequeue();
        
        var temp = q1;
        q1 = q2;
        q2 = temp;
    

    /**
     * Removes the element on top of the stack and returns that element.
     */
    public int Pop() 
        count--;
        return q2.Dequeue();
    

    /**
     * Get the top element.
     */
    public int Top() 
        return q2.Peek();
    

    /**
     * Returns whether the stack is empty.
     */
    public bool Empty() 
        if (count > 0) return false;
        return true;
    

【讨论】:

【参考方案5】:

下面是一个非常简单的Java解决方案,它支持高效的推送操作。

算法 -

    声明两个队列 q1 和 q2。

    推送操作 - 将元素加入队列 q1。

    Pop 操作 - 确保队列 q2 不为空。如果是空的, 然后将除最后一个元素之外的所有元素从 q1 中出列,并且 将其一一排入q2。从 q1 中取出最后一个元素,然后 将其存储为弹出元素。交换队列 q1 和 q2。返回 存储的弹出元素。

    Peek 操作 - 确保队列 q2 不为空。如果是空的, 然后将除最后一个元素之外的所有元素从 q1 中出列,并且 将其一一排入q2。从 q1 中取出最后一个元素,然后 将其存储为偷看的元素。将其排回队列 q2 并交换 队列 q1 和 q2。返回存储的 peeked 元素。

以下是上述算法的代码-

class MyStack 

    java.util.Queue<Integer> q1;
    java.util.Queue<Integer> q2;
    int SIZE = 0;

    /** Initialize your data structure here. */
    public MyStack() 
        q1 = new LinkedList<Integer>();
        q2 = new LinkedList<Integer>();

    

    /** Push element x onto stack. */
    public void push(int x) 
        q1.add(x);
        SIZE ++;

    

    /** Removes the element on top of the stack and returns that element. */
    public int pop() 
        ensureQ2IsNotEmpty();
        int poppedEle = q1.remove();
        SIZE--;
        swapQueues();
        return poppedEle;
    

    /** Get the top element. */
    public int top() 
        ensureQ2IsNotEmpty();
        int peekedEle = q1.remove();
        q2.add(peekedEle);
        swapQueues();
        return peekedEle;
    

    /** Returns whether the stack is empty. */
    public boolean empty() 
        return q1.isEmpty() && q2.isEmpty();

    

    /** move all elements from q1 to q2 except last element */
    public void ensureQ2IsNotEmpty() 
        for(int i=0; i<SIZE-1; i++) 
            q2.add(q1.remove());
        
    

    /** Swap queues q1 and q2 */
    public void swapQueues() 
        Queue<Integer> temp = q1;
        q1 = q2;
        q2 = temp;
    

【讨论】:

【参考方案6】:

这是一个非常简单的解决方案,它使用一个队列并提供像堆栈这样的功能。

public class CustomStack<T>

    Queue<T> que = new Queue<T>();

    public void push(T t) // STACK = LIFO / QUEUE = FIFO
    

        if( que.Count == 0)
        
            que.Enqueue(t);
        
        else
        
            que.Enqueue(t);
            for (int i = 0; i < que.Count-1; i++)
            
                var data = que.Dequeue();

                que.Enqueue(data);
            
        

    

    public void pop()
    

        Console.WriteLine("\nStack Implementation:");
        foreach (var item in que)
        
            Console.Write("\n" + item.ToString() + "\t");
        

        var data = que.Dequeue();
        Console.Write("\n Dequeing :" + data);
    

    public void top()
    

        Console.Write("\n Top :" + que.Peek());
    



所以在上面名为“CustomStack”的类中,我所做的只是检查队列是否为空,如果为空,则插入一个,然后从病房插入,然后删除插入。按照这个逻辑,先到先得。 示例:在队列中我插入了 1,现在尝试插入 2。第二次删除 1 并再次插入,因此它变成了相反的顺序。

谢谢。

【讨论】:

【参考方案7】:

版本A(高效推送):

推送: 在 queue1 中排队 弹出: 当 queue1 的大小大于 1 时,将队列 1 中的出列项通过管道传输到 queue2 中 出队并返回queue1的最后一项,然后切换queue1和queue2的名称

版本 B(高效弹出):

推送: 在 queue2 中排队 将queue1的所有项入队queue2,然后切换queue1和queue2的名称 弹出: 从 queue1 出队

【讨论】:

版本 B 似乎有问题:您的意思是将 queue2 的所有项目排入队列 1,除了最后一个元素(然后切换 q1 和 q2 的名称)? Icerman 的评论对我来说很有意义。答案的版本 B 需要编辑。我没有编辑权限。有人可以编辑这个答案吗? @eeerahul:我又查了一遍,答案是正确的。当时 Icerman 似乎想将 queue2 的所有项目排入队列 1,而 queue2 仅包含新项目,因此该评论 not 有意义。 A 版对吗? push 1, push 2, push 3, push 4. pop 4. push 5, push 6, push 7, push 8. pop 8. pop 7. 好像那个算法会弹出 3 而不是 7. 你的算法似乎正确乍一看,因为我们可能会这样推断:基本上,您将始终弹出队列 1 中最后一个入队的元素。但只有在您之前排队时,这才是最后一个推送的元素。如果您连续弹出多次,则不一定是这样。 @user127.0.0.1:您似乎忘记在每次弹出结束时切换队列。有一个不变量,每次push和pop后,所有item都在queue1,而queue2是空的。【参考方案8】:

这是完整的 c# 工作代码:

已经用单队列实现了,

推:

1. add new element.
2. Remove elements from Queue (totalsize-1) times and add back to the Queue

弹出:

normal remove





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

    namespace StackImplimentationUsingQueue
    
        class Program
        
            public class Node
            
                public int data;
                public Node link;
            
            public class Queue
            
                public Node rear;
                public Node front;
                public int size = 0;
                public void EnQueue(int data)
                
                    Node n = new Node();
                    n.data = data;
                    n.link = null;
                    if (rear == null)
                        front = rear = n;
                    else
                    
                        rear.link = n;
                        rear = n;
                    
                    size++;
                    Display();
                
                public Node DeQueue()
                
                    Node temp = new Node();
                    if (front == null)
                        Console.WriteLine("Empty");
                    else
                    
                        temp = front;
                        front = front.link;
                        size--;
                    
                    Display();
                    return temp;
                
                public void Display()
                
                    if (size == 0)
                        Console.WriteLine("Empty");
                    else
                    
                        Console.Clear();
                        Node n = front;
                        while (n != null)
                        
                            Console.WriteLine(n.data);
                            n = n.link;
                        
                    
                
            
            public class Stack
            
                public Queue q;
                public int size = 0;
                public Node top;
                public Stack()
                
                    q = new Queue();
                
                public void Push(int data)
                
                    Node n = new Node();
                    n.data = data;
                    q.EnQueue(data);
                    size++;
                    int counter = size;
                    while (counter > 1)
                    
                        q.EnQueue(q.DeQueue().data);
                        counter--;
                    
                
                public void Pop()
                
                    q.DeQueue();
                    size--;
                
            
            static void Main(string[] args)
            
                Stack s= new Stack();
                for (int i = 1; i <= 3; i++)
                    s.Push(i);
                for (int i = 1; i < 3; i++)
                    s.Pop();
                Console.ReadKey();
            
        
    

【讨论】:

是否愿意根据当前保留的元素/推送和弹出的总和来评论您的实现所需的(预期/摊销)时间?【参考方案9】:

仅使用一个队列的 Python 代码

 class Queue(object):
    def __init__(self):
        self.items=[]
    def enqueue(self,item):
        self.items.insert(0,item)
    def dequeue(self):
        if(not self.isEmpty()):
            return  self.items.pop()
    def isEmpty(self):
        return  self.items==[]
    def size(self):
        return len(self.items)



class stack(object):
        def __init__(self):
            self.q1= Queue()


        def push(self, item):
            self.q1.enqueue(item) 


        def pop(self):
            c=self.q1.size()
            while(c>1):
                self.q1.enqueue(self.q1.dequeue())
                c-=1
            return self.q1.dequeue()



        def size(self):
            return self.q1.size() 


        def isempty(self):
            if self.size > 0:
               return True
            else:
               return False

【讨论】:

请尽量避免只是将代码作为答案转储,并尝试解释它的作用和原因。对于没有相关编码经验的人来说,您的代码可能并不明显。【参考方案10】:
import java.util.LinkedList;
import java.util.Queue;

class MyStack 
    Queue<Integer> queue1 = new LinkedList<Integer>();
    Queue<Integer> queue2 = new LinkedList<Integer>();

    // Push element x onto stack.
    public void push(int x) 
        if(isEmpty())
            queue1.offer(x);
        else
            if(queue1.size()>0)
                queue2.offer(x);
                int size = queue1.size();
                while(size>0)
                    queue2.offer(queue1.poll());
                    size--;
                
            else if(queue2.size()>0)
                queue1.offer(x);
                int size = queue2.size();
                while(size>0)
                    queue1.offer(queue2.poll());
                    size--;
                
            
        
    

    // Removes the element on top of the stack.
    public void pop() 
        if(queue1.size()>0)
            queue1.poll();
        else if(queue2.size()>0)
            queue2.poll();
        
    

    // Get the top element. You can make it more perfect just example
    public int top() 
       if(queue1.size()>0)
            return queue1.peek();
        else if(queue2.size()>0)
            return queue2.peek();
        
        return 0;
    

    // Return whether the stack is empty.
    public boolean isEmpty() 
        return queue1.isEmpty() && queue2.isEmpty();
    

【讨论】:

【参考方案11】:
Q1 = [10, 15, 20, 25, 30]
Q2 = []

exp:
   
    dequeue n-1 element from Q1 and enqueue into Q2: Q2 == [10, 15, 20, 25]

    now Q1 dequeue gives "30" that inserted last and working as stack


swap Q1 and Q2 then GOTO exp

【讨论】:

【参考方案12】:
#include "stdio.h"
#include "stdlib.h"

typedef struct 
    int *q;
    int size;
    int front;
    int rear;
 Queue;
typedef struct 
    Queue *q1;
    Queue *q2;
 Stack;

int queueIsEmpty(Queue *q) 
    if (q->front == -1 && q->rear == -1) 
        printf("\nQUEUE is EMPTY\n");
        return 1;
    
    return 0;

int queueIsFull(Queue *q) 
    if (q->rear == q->size-1) 
        return 1;
    
    return 0;

int queueTop(Queue *q) 
    if (queueIsEmpty(q)) 
        return -1;
    
    return q->q[q->front];

int queuePop(Queue *q) 
    if (queueIsEmpty(q)) 
        return -1;
    
    int item = q->q[q->front];
    if (q->front == q->rear) 
        q->front = q->rear = -1;
    
    else 
        q->front++;
    
    return item;

void queuePush(Queue *q, int val) 
    if (queueIsFull(q)) 
        printf("\nQUEUE is FULL\n");
        return;
    
    if (queueIsEmpty(q)) 
        q->front++;
        q->rear++;
     else 
        q->rear++;
    
    q->q[q->rear] = val;

Queue *queueCreate(int maxSize) 
    Queue *q = (Queue*)malloc(sizeof(Queue));
    q->front = q->rear = -1;
    q->size = maxSize;
    q->q = (int*)malloc(sizeof(int)*maxSize);
    return q;

/* Create a stack */
void stackCreate(Stack *stack, int maxSize) 
    Stack **s = (Stack**) stack;
    *s = (Stack*)malloc(sizeof(Stack));
    (*s)->q1 = queueCreate(maxSize);
    (*s)->q2 = queueCreate(maxSize);


/* Push element x onto stack */
void stackPush(Stack *stack, int element) 
    Stack **s = (Stack**) stack;
    queuePush((*s)->q2, element);
    while (!queueIsEmpty((*s)->q1)) 
        int item = queuePop((*s)->q1);
        queuePush((*s)->q2, item);
    
    Queue *tmp = (*s)->q1;
    (*s)->q1 = (*s)->q2;
    (*s)->q2 = tmp;


/* Removes the element on top of the stack */
void stackPop(Stack *stack) 
    Stack **s = (Stack**) stack;
    queuePop((*s)->q1);


/* Get the top element */
int stackTop(Stack *stack) 
    Stack **s = (Stack**) stack;
    if (!queueIsEmpty((*s)->q1)) 
      return queueTop((*s)->q1);
    
    return -1;


/* Return whether the stack is empty */
bool stackEmpty(Stack *stack) 
    Stack **s = (Stack**) stack;
    if (queueIsEmpty((*s)->q1)) 
        return true;
    
    return false;


/* Destroy the stack */
void stackDestroy(Stack *stack) 
    Stack **s = (Stack**) stack;
    free((*s)->q1);
    free((*s)->q2);
    free((*s));


int main()

  Stack *s = NULL;
  stackCreate((Stack*)&s, 10);
  stackPush((Stack*)&s, 44);
  //stackPop((Stack*)&s);
  printf("\n%d", stackTop((Stack*)&s));
  stackDestroy((Stack*)&s);
  return 0;

【讨论】:

没有 cmets 或解释的代码墙是一个糟糕的答案。【参考方案13】:
import java.util.LinkedList;
import java.util.Queue;


public class StackQueue 

    static Queue<Integer> Q1 = new LinkedList<Integer>();
    static Queue<Integer> Q2 = new LinkedList<Integer>();
    public static void main(String args[]) 



        push(24);
        push(34);
        push(4);
        push(10);
        push(1);
        push(43);
        push(21);
        System.out.println("Popped element is  "+pop());
        System.out.println("Popped element is  "+pop());
        System.out.println("Popped element is  "+pop());


    

    public static void push(int data) 

        Q1.add(data);

    

    public static int pop() 

        if(Q1.isEmpty()) 
        System.out.println("Cannot pop elements ,  Stack is Empty !!"); 
        return -1;
        
        else
        
        while(Q1.size() > 1) 
            Q2.add(Q1.remove());
        
        int element = Q1.remove();
        Queue<Integer> temp = new LinkedList<Integer>();
        temp = Q1;
        Q1 = Q2;
        Q2 = temp;
        return element;
        
    

【讨论】:

Java 链表可以用作双端队列。这个答案没有意义。【参考方案14】:

我们可以只使用一个队列来实现堆栈吗?我可以使用两个队列,但考虑单个队列会更有效。代码如下:

    public void Push(T val)
    
        queLower.Enqueue(val);
    

    public  T Pop()
    

        if (queLower.Count == 0 )
        
            Console.Write("Stack is empty!");
            return default(T);

         
        if (queLower.Count > 0)
        
            for (int i = 0; i < queLower.Count - 1;i++ )
            
                queLower.Enqueue(queLower.Dequeue ());
           
                    

        return queLower.Dequeue();

    

【讨论】:

我猜在 pop 方法中,for 循环条件应该是 i 因为你用 0 初始化变量 i。【参考方案15】:

这是我的解决方案..

Concept_Behind:: push(struct Stack* S,int data)::此函数将 Q1 中的第一个元素入队并在 Q2 中休息 pop(struct Stack* S)::如果 Q2 不为空,则将所有 elem 转移到 Q1 并返回 Q2 中的最后一个 elem else(表示 Q2 为空)将所有元素转移到 Q2 并返回 Q1 中的最后一个元素

Efficiency_Behind:: push(struct Stack*S,int data)::O(1)//因为每个数据单个入队 pop(struct Stack* S)::O(n)//因为每次pop传输最差的n-1个数据。

#include<stdio.h>
#include<stdlib.h>
struct Queue
    int front;
    int rear;
    int *arr;
    int size;
    ;
struct Stack 
    struct Queue *Q1;
    struct Queue *Q2;
    ;
struct Queue* Qconstructor(int capacity)

    struct Queue *Q=malloc(sizeof(struct Queue));
    Q->front=Q->rear=-1;
    Q->size=capacity;
    Q->arr=malloc(Q->size*sizeof(int));
    return Q;
    
int isEmptyQueue(struct Queue *Q)

    return (Q->front==-1);
    
int isFullQueue(struct Queue *Q)

    return ((Q->rear+1) % Q->size ==Q->front);
    
void enqueue(struct Queue *Q,int data)

    if(isFullQueue(Q))
        
            printf("Queue overflow\n");
            return;
    Q->rear=Q->rear+1 % Q->size;
    Q->arr[Q->rear]=data;
    if(Q->front==-1)
        Q->front=Q->rear;
        
int dequeue(struct Queue *Q)

    if(isEmptyQueue(Q))
        printf("Queue underflow\n");
        return;
        
    int data=Q->arr[Q->front];
    if(Q->front==Q->rear)
        Q->front=-1;
    else
    Q->front=Q->front+1 % Q->size;
    return data;
    
///////////////////////*************main algo****************////////////////////////
struct Stack* Sconstructor(int capacity)

    struct Stack *S=malloc(sizeof(struct Stack));
    S->Q1=Qconstructor(capacity);
    S->Q2=Qconstructor(capacity);
    return S;

void push(struct Stack *S,int data)

    if(isEmptyQueue(S->Q1))
        enqueue(S->Q1,data);
    else
        enqueue(S->Q2,data);
    
int pop(struct Stack *S)

    int i,tmp;
    if(!isEmptyQueue(S->Q2))
        for(i=S->Q2->front;i<=S->Q2->rear;i++)
            tmp=dequeue(S->Q2);
            if(isEmptyQueue(S->Q2))
                return tmp;
            else
                enqueue(S->Q1,tmp);
                
            
    else
        for(i=S->Q1->front;i<=S->Q1->rear;i++)
            tmp=dequeue(S->Q1);
            if(isEmptyQueue(S->Q1))
                return tmp;
            else
                enqueue(S->Q2,tmp);
                
            
        
////////////////*************end of main algo my algo************
///////////////*************push() O(1);;;;pop() O(n);;;;*******/////
main()

    int size;
    printf("Enter the number of elements in the Stack(made of 2 queue's)::\n");
    scanf("%d",&size);
    struct Stack *S=Sconstructor(size);
    push(S,1);
    push(S,2);
    push(S,3);
    push(S,4);
    printf("%d\n",pop(S));
    push(S,5);
    printf("%d\n",pop(S));
    printf("%d\n",pop(S));
    printf("%d\n",pop(S));
    printf("%d\n",pop(S));
    

【讨论】:

【参考方案16】:
#include <bits/stdc++.h>
using namespace std;
queue<int>Q;
stack<int>Stk;
void PRINT(stack<int>ss , queue<int>qq) 
    while( ss.size() ) 
        cout << ss.top() << " " ;
        ss.pop();
    
    puts("");
    while( qq.size() ) 
        cout << qq.front() << " " ;
        qq.pop();
    
    puts("\n----------------------------------");

void POP() 
    queue<int>Tmp ;
    while( Q.size() > 1 ) 
        Tmp.push( Q.front()  );
        Q.pop();
    
    cout << Q.front() << " " << Stk.top() << endl;
    Q.pop() , Stk.pop() ;
    Q = Tmp ;

void PUSH(int x ) 
    Q.push(x);
    Stk.push(x);

int main() 
    while( true ) 
        string typ ;
        cin >> typ ;
        if( typ == "push" ) 
            int x ;
            cin >> x;
            PUSH(x);
         else POP();
        PRINT(Stk,Q);
    

【讨论】:

请一些话,解释这段代码是关于什么的,以及这个东西如何帮助 OP 解决他/她的问题,将不胜感激,连同代码示例 :-) 【参考方案17】:

设 S1 和 S2 为用于实现队列的两个 Stack。

struct Stack 
 struct Queue *Q1;
  struct Queue *Q2;

我们确保一个队列始终为空。

推送操作: 无论哪个队列不为空,将元素插入其中。

检查队列 Q1 是否为空。如果 Q1 为空,则将其中的元素入队。 否则将元素排队到 Q1。

Push (struct Stack *S, int data) if(isEmptyQueue(S->Q1) EnQueue(S->Q2, data); else EnQueue(S->Q1, data);

时间复杂度:O(1)

Pop 操作: 将 n-1 个元素转移到其他队列中并从队列中删除最后一个以执行 pop 操作。

如果队列 Q1 不为空,则将 n-1 个元素从 Q1 传输到 Q2,然后将 Q1 的最后一个元素出列并返回。 如果队列 Q2 不为空,则将 n-1 个元素从 Q2 传输到 Q1,然后将 Q2 的最后一个元素出列并返回。

`

int Pop(struct Stack *S)
int i, size;
if(IsEmptyQueue(S->Q2)) 

size=size(S->Q1);
i=0;
while(i<size-1)
 EnQueue(S->Q2, Dequeue(S->Q1)) ;
  i++;

return DeQueue(S->Q1);  

else
size=size(S->Q2);
while(i<size-1)
EnQueue(S->Q1, Dequeue(S->Q2)) ;
i++;

return DeQueue(S->Q2);
 

时间复杂度:pop 操作的运行时间为 O(n),因为每次调用 pop 时,我们都将所有元素从一个队列转移到其他队列。

【讨论】:

【参考方案18】:

这里是一些简单的伪代码,push是O(n),pop/peek是O(1):

Qpush = Qinstance()
Qpop = Qinstance()

def stack.push(item):
    Qpush.add(item)
    while Qpop.peek() != null: //transfer Qpop into Qpush
        Qpush.add(Qpop.remove()) 
    swap = Qpush
    Qpush = Qpop
    Qpop = swap

def stack.pop():
    return Qpop.remove()

def stack.peek():
    return Qpop.peek()

【讨论】:

【参考方案19】:

这是我在平均情况下适用于 O(1) 的解决方案。有两个队列:inout。见伪代码如下:

PUSH(X) = in.enqueue(X)

POP: X =
  if (out.isEmpty and !in.isEmpty)
    DUMP(in, out)
  return out.dequeue

DUMP(A, B) =
  if (!A.isEmpty)
    x = A.dequeue()
    DUMP(A, B)
    B.enqueue(x)

【讨论】:

你正在使用 2 个队列和 1 个堆栈来模拟 1 个堆栈! 你的意思是隐式递归堆栈吗?【参考方案20】:
import java.util.*;

/**
 *
 * @author Mahmood
 */
public class StackImplUsingQueues 

    Queue<Integer> q1 = new LinkedList<Integer>();
    Queue<Integer> q2 = new LinkedList<Integer>();

    public int pop() 
        if (q1.peek() == null) 
            System.out.println("The stack is empty, nothing to return");
            int i = 0;
            return i;
         else 
            int pop = q1.remove();
            return pop;
        
    

    public void push(int data) 

        if (q1.peek() == null) 
            q1.add(data);
         else 
            for (int i = q1.size(); i > 0; i--) 
                q2.add(q1.remove());
            
            q1.add(data);
            for (int j = q2.size(); j > 0; j--) 
                q1.add(q2.remove());
            

        
    

    public static void main(String[] args) 
        StackImplUsingQueues s1 = new StackImplUsingQueues();
        //       Stack s1 = new Stack();
        s1.push(1);
        s1.push(2);
        s1.push(3);
        s1.push(4);
        s1.push(5);
        s1.push(6);
        s1.push(7);
        s1.push(8);
        s1.push(9);
        s1.push(10);
        // s1.push(6);
        System.out.println("1st = " + s1.pop());
        System.out.println("2nd = " + s1.pop());
        System.out.println("3rd = " + s1.pop());
        System.out.println("4th = " + s1.pop());
        System.out.println("5th = " + s1.pop());
        System.out.println("6th = " + s1.pop());
        System.out.println("7th = " + s1.pop());
        System.out.println("8th = " + s1.pop());
        System.out.println("9th = " + s1.pop());
        System.out.println("10th= " + s1.pop());
    

【讨论】:

有人能解释一下上面代码中push方法背后的登录吗?据我了解,第一个 for 循环是将所有元素删除到 q2 中,直到 q1 剩下一个元素。如果我错了,请纠正我。【参考方案21】:

这里还有一个解决方案:

对于推送: - 在队列 1 中添加第一个元素。 -当添加第二个元素等时, 首先将队列 2 中的元素排入队列,然后将队列 1 中的所有元素复制到队列 2。 -对于 POP,只需从插入最后一个元素的队列中取出元素。

所以,

public void push(int data)
if (queue1.isEmpty())
    queue1.enqueue(data);
  else 
queue2.enqueue(data);
while(!queue1.isEmpty())
Queue2.enqueue(queue1.dequeue());
//EXCHANGE THE NAMES OF QUEUE 1 and QUEUE2

public int pop()
int popItem=queue2.dequeue();
return popItem;
'

有一个问题,我想不通,如何重命名队列???

【讨论】:

【参考方案22】:

我们可以用一个队列做到这一点:

推:

    将新元素加入队列。 如果 n 是队列中的元素数,则删除和插入元素 n-1 次。

弹出:

    出队

.

push 1


front                     
+----+----+----+----+----+----+
| 1  |    |    |    |    |    |    insert 1
+----+----+----+----+----+----+


push2

front                     
+----+----+----+----+----+----+
| 1  | 2  |    |    |    |    |    insert 2
+----+----+----+----+----+----+

     front                     
+----+----+----+----+----+----+
|    | 2  |  1 |    |    |    |    remove and insert 1
+----+----+----+----+----+----+




 insert 3


      front                     
+----+----+----+----+----+----+
|    | 2  |  1 |  3 |    |    |    insert 3
+----+----+----+----+----+----+

           front                     
+----+----+----+----+----+----+
|    |    |  1 |  3 |  2 |    |    remove and insert 2
+----+----+----+----+----+----+

                front                     
+----+----+----+----+----+----+
|    |    |    |  3 |  2 |  1 |    remove and insert 1
+----+----+----+----+----+----+

示例实现:

int stack_pop (queue_data *q)

  return queue_remove (q);


void stack_push (queue_data *q, int val)

  int old_count = queue_get_element_count (q), i;

  queue_insert (q, val);
  for (i=0; i<old_count; i++)
  
    queue_insert (q, queue_remove (q));
  

【讨论】:

【参考方案23】:
queue<int> q1, q2;
int i = 0;

void push(int v) 
  if( q1.empty() && q2.empty() ) 
     q1.push(v);
     i = 0;
  
  else 
     if( i == 0 ) 
        while( !q1.empty() ) q2.push(q1.pop());
        q1.push(v);
        i = 1-i;
     
     else 
        while( !q2.empty() ) q1.push(q2.pop());
        q2.push(v);
        i = 1-i;
     
  


int pop() 
   if( q1.empty() && q2.empty() ) return -1;
   if( i == 1 ) 
      if( !q1.empty() )
           return q1.pop();
      else if( !q2.empty() )
           return q2.pop();
   
   else 
      if( !q2.empty() )
           return q2.pop();
      else if( !q1.empty() )
           return q1.pop();
   

【讨论】:

【参考方案24】:

如前所述,难道不是一个队列就可以解决问题吗?它可能不太实用,但有点圆滑。

push(x):
enqueue(x)
for(queueSize - 1)
   enqueue(dequeue())

pop(x):
dequeue()

【讨论】:

【参考方案25】:

这是我的答案——“流行音乐”效率低下。 似乎所有立即想到的算法都有 N 复杂度,其中 N 是列表的大小:无论您选择在“pop”上工作还是在“push”上工作

列表交换和第四次交换的算法可能更好, 因为不需要计算大小,尽管您仍然需要循环并与空进行比较。

你可以证明这个算法的编写速度不能比 N 快,方法是注意到关于队列中最后一个元素的信息只有通过知道队列的大小才能获得,并且你必须销毁数据才能到达该元素,因此第二个队列。

使这更快的唯一方法是首先不使用队列。

from data_structures import queue

class stack(object):
    def __init__(self):
        q1= queue 
        q2= queue #only contains one item at most. a temp var. (bad?)

    def push(self, item):
        q1.enque(item) #just stick it in the first queue.

    #Pop is inefficient
    def pop(self):
        #'spin' the queues until q1 is ready to pop the right value. 
        for N 0 to self.size-1
            q2.enqueue(q1.dequeue)
            q1.enqueue(q2.dequeue)
        return q1.dequeue()

    @property
    def size(self):
        return q1.size + q2.size

    @property
    def isempty(self):
        if self.size > 0:
           return True
        else
           return False

【讨论】:

【参考方案26】:

最简单的(也许是唯一的)方法是将新元素推入空队列,然后将另一个元素出队并入队到先前的空队列中。通过这种方式,最新的总是排在队列的前面。这将是版本 B,对于版本 A,您只需将元素出列到第二个队列中,最后一个队列除外。

第 0 步:

"Stack"
+---+---+---+---+---+
|   |   |   |   |   |
+---+---+---+---+---+

Queue A                Queue B
+---+---+---+---+---+  +---+---+---+---+---+
|   |   |   |   |   |  |   |   |   |   |   |
+---+---+---+---+---+  +---+---+---+---+---+

第 1 步:

"Stack"
+---+---+---+---+---+
| 1 |   |   |   |   |
+---+---+---+---+---+

Queue A                Queue B
+---+---+---+---+---+  +---+---+---+---+---+
| 1 |   |   |   |   |  |   |   |   |   |   |
+---+---+---+---+---+  +---+---+---+---+---+

第 2 步:

"Stack"
+---+---+---+---+---+
| 2 | 1 |   |   |   |
+---+---+---+---+---+

Queue A                Queue B
+---+---+---+---+---+  +---+---+---+---+---+
|   |   |   |   |   |  | 2 | 1 |   |   |   |
+---+---+---+---+---+  +---+---+---+---+---+

第 3 步:

"Stack"
+---+---+---+---+---+
| 3 | 2 | 1 |   |   |
+---+---+---+---+---+

Queue A                Queue B
+---+---+---+---+---+  +---+---+---+---+---+
| 3 | 2 | 1 |   |   |  |   |   |   |   |   |
+---+---+---+---+---+  +---+---+---+---+---+

【讨论】:

这个逻辑没有任何意义。从第 2 步移到第 3 步。当我“推”3 时,我怎样才能使队列 B 中的元素出队,以便在队列 A 中得到 3 2 1?如果我将 B 出队到入队 A,我只能按 2、1 的顺序获取元素。如果我再添加 3,我将得到 3、1、2 的顺序。如果先推送,然后再出队/入队,我得到1、2、3。 为什么不让 deque 操作比 enqueue 操作更昂贵?

以上是关于使用两个队列实现堆栈的主要内容,如果未能解决你的问题,请参考以下文章

两个堆栈实现列队

用堆栈实现队列

AcWing36:用两个栈实现队列

AcWing36:用两个栈实现队列

为啥我们要“使用 2 个堆栈实现一个队列”? [复制]

PTA-7-22 堆栈模拟队列