it-swarm.it

Come implementare una coda usando due stack?

Supponiamo di avere due stack e nessun'altra variabile temporanea.

È possibile "costruire" una struttura dati di coda usando solo i due stack?

362
Nitin

Mantieni 2 stack, chiamiamoli inbox e outbox.

Enqueue :

  • Spingi il nuovo elemento su inbox

Dequeue :

  • Se outbox è vuoto, riempilo facendo scoppiare ogni elemento da inbox e spingendolo su outbox

  • Pop e restituisce l'elemento superiore da outbox

Usando questo metodo, ogni elemento si troverà in ogni pila esattamente una volta - il che significa che ogni elemento sarà spinto due volte e fatto scoppiare due volte, dando operazioni a tempo costante ammortizzato.

Ecco un'implementazione 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();
    }

}
665
Dave L.

A - Come rovesciare una pila

Per capire come costruire una coda usando due stack, dovresti capire come invertire una pila cristallina. Ricorda come funziona lo stack, è molto simile alla pila di piatti sulla tua cucina. L'ultimo piatto lavato si troverà in cima alla pila pulita, che viene chiamato come L ast I n F irst O ut (LIFO) in informatica.

Immaginiamo il nostro stack come una bottiglia come di seguito;

 enter image description here

Se spingiamo gli interi 1,2,3 rispettivamente, quindi 3 sarà in cima alla pila. Dato che 1 sarà spinto per primo, allora 2 sarà messo in cima a 1. Infine, 3 sarà messo in cima allo stack e l'ultimo stato del nostro stack rappresentato come una bottiglia sarà come sotto;

 enter image description here

Ora abbiamo il nostro stack rappresentato mentre una bottiglia è popolata con i valori 3,2,1. E vogliamo invertire lo stack in modo che l'elemento in cima allo stack sia 1 e l'elemento in basso dello stack sarà 3. Cosa possiamo fare? Possiamo prendere la bottiglia e tenerla sottosopra in modo che tutti i valori debbano essere invertiti in ordine?

 enter image description here

Sì, possiamo farlo, ma questa è una bottiglia. Per fare lo stesso processo, abbiamo bisogno di avere un secondo stack su cui archiviare i primi elementi dello stack in ordine inverso. Mettiamo il nostro stack popolato a sinistra e il nostro nuovo stack vuoto a destra. Per invertire l'ordine degli elementi, inseriremo ciascun elemento dalla pila di sinistra e li spingeremo nello stack di destra. Puoi vedere cosa succede mentre lo facciamo sull'immagine qui sotto;

 enter image description here

Quindi sappiamo come invertire una pila.

B - Utilizzo di due pile come coda

Nella parte precedente, ho spiegato come possiamo invertire l'ordine degli elementi dello stack. Questo era importante, perché se spingiamo e popiamo elementi nello stack, l'output sarà esattamente nell'ordine inverso di una coda. Pensando ad un esempio, spingiamo l'array di interi {1, 2, 3, 4, 5} in uno stack. Se inseriamo gli elementi e li stampiamo fino a quando lo stack non è vuoto, otterremo l'array nell'ordine inverso di ordine push, che sarà {5, 4, 3, 2, 1} Ricorda che per lo stesso input, se rimuoviamo la coda finché la coda non è vuota, il l'output sarà {1, 2, 3, 4, 5}. Quindi è ovvio che per lo stesso ordine di input di elementi, l'output della coda è esattamente al contrario dell'output di uno stack. Poiché sappiamo come invertire uno stack usando uno stack extra, possiamo costruire una coda usando due stack.

Il nostro modello di coda sarà composto da due pile. Uno stack sarà usato per l'operazione enqueue (lo stack n. 1 a sinistra, sarà chiamato come Input Stack), un altro stack verrà usato per l'operazione dequeue (lo stack n. 2 a destra, sarà chiamato come Output Stack). Guarda l'immagine qui sotto;

 enter image description here

Il nostro pseudo-codice è il seguente;


Accendi il funzionamento

Push every input element to the Input Stack

Rimboccare l'operazione

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

Accodiamo rispettivamente gli interi {1, 2, 3}. I numeri interi verranno inseriti nello Input Stack (Stack # 1) che si trova a sinistra;

 enter image description here

Quindi cosa succederà se eseguiremo un'operazione di dequeue? Ogni volta che viene eseguita un'operazione di dequeue, la coda controlla se lo stack di output è vuoto o meno (vedere lo pseudo-codice sopra) Se lo stack di output è vuoto, lo stack di input verrà estratto sull'output in modo che gli elementi di Input Stack sarà invertito. Prima di restituire un valore, lo stato della coda sarà il seguente;

 enter image description here

Controlla l'ordine degli elementi nello Stack di output (Stack # 2). È ovvio che siamo in grado di estrarre gli elementi dallo stack di output in modo che l'output sia lo stesso di quello che abbiamo rimosso dalla coda. Quindi, se eseguiamo due operazioni di dequeue, prima otterremo {1, 2} rispettivamente. Quindi l'elemento 3 sarà l'unico elemento dello stack di output e lo stack di input sarà vuoto. Se accodiamo gli elementi 4 e 5, lo stato della coda sarà il seguente;

 enter image description here

Ora lo stack di output non è vuoto e se eseguiamo un'operazione di dequeue, solo 3 verranno estratti dallo stack di output. Allora lo stato sarà visto come sotto;

 enter image description here

Di nuovo, se eseguiamo altre due operazioni di dequeue, sulla prima operazione di rimozione, la coda controllerà se lo Stack di output è vuoto, il che è vero. Quindi esponi gli elementi dello stack di input e spingili allo stack di output finché lo stack di input non è vuoto, quindi lo stato della coda sarà il seguente;

 enter image description here

Facile da vedere, l'output delle due operazioni di dequeue sarà {4, 5}

C - Implementazione della coda costruita con due pile

Ecco un'implementazione in Java. Non ho intenzione di utilizzare l'implementazione esistente di Stack, quindi l'esempio qui reinventerà la ruota;

C - 1) Classe MyStack: un'implementazione Simple Stack

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) Classe MyQueue: implementazione della coda utilizzando due stack

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) Codice demo

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) Uscita campione

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

Puoi anche simulare una coda usando solo una pila. Il secondo stack (temporaneo) può essere simulato dallo stack di chiamate di chiamate ricorsive al metodo di inserimento. 

Il principio rimane lo stesso quando si inserisce un nuovo elemento nella coda: 

  • È necessario trasferire elementi da una pila a un'altra pila temporanea, per invertire il loro ordine. 
  • Quindi spingere il nuovo elemento da inserire, sulla pila temporanea
  • Quindi trasferisci gli elementi nella pila originale
  • Il nuovo elemento sarà nella parte inferiore della pila e l'elemento più vecchio è in cima (prima a essere spuntato)

Una classe di coda che utilizza solo uno stack, sarebbe la seguente:

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

Le complessità del tempo sarebbero peggiori, però. Una buona implementazione della coda fa tutto in tempo costante.

Modificare

Non sono sicuro del motivo per cui la mia risposta è stata downvoted qui. Se programmiamo, ci preoccupiamo della complessità del tempo e l'uso di due stack standard per fare in modo che una coda sia inefficiente. È un punto molto valido e pertinente. Se qualcun altro sentisse il bisogno di downvotare di più, sarei interessato a sapere perché.

Un po 'più in dettaglio: sul perché usare due stack è peggio di una coda: se usi due stack, e qualcuno chiama dequeue mentre la posta in uscita è vuota, hai bisogno di tempo lineare per arrivare alla fine della posta in arrivo ( come puoi vedere nel codice di Dave).

È possibile implementare una coda come un elenco collegato singolarmente (ogni elemento punta all'elemento inserito successivamente), mantenendo un puntatore aggiuntivo sull'elemento inserito per ultimo per i push (o rendendolo un elenco ciclico). L'implementazione di code e dequeue su questa struttura dati è molto semplice da eseguire in tempo costante. Questo è il peggior tempo costante, non ammortizzato. E, poiché i commenti sembrano chiedere questo chiarimento, il tempo costante nel caso peggiore è strettamente migliore del tempo costante ammortizzato.

11
Tyler

Lascia che la coda sia implementata q e gli stack usati per implementare q essere stack1 e stack2. 

q può essere implementato in two ways:

Metodo 1 (rendendo costosa l'operazione enQueue)

Questo metodo si assicura che l'elemento appena inserito sia sempre nella parte superiore dello stack 1, in modo che l'operazione deQueue venga semplicemente visualizzata dallo stack1. Per mettere l'elemento in cima allo stack1, viene usato lo 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.

Metodo 2 (rendendo costosa l'operazione deQueue)

In questo metodo, nell'operazione di en-queue, il nuovo elemento viene inserito nella parte superiore dello stack1. Nell'operazione di de-queue, se stack2 è vuoto, tutti gli elementi vengono spostati nello stack2 e infine viene restituito l'inizio dello 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.

Il metodo 2 è decisamente migliore del metodo 1. Il metodo 1 sposta tutti gli elementi due volte nell'operazione enQueue, mentre il metodo 2 (nell'operazione deQueue) sposta gli elementi una volta e sposta gli elementi solo se stack2 è vuoto.

7
Rahul Gandhi

Una soluzione 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();
        }
}
3
Santhosh

Dovrai far saltare tutto dal primo stack per ottenere l'elemento inferiore. Quindi rimettili tutti nella seconda pila per ogni operazione di "rimozione".

2
user11055

per lo sviluppatore c # ecco il programma completo:

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

Due stack in coda sono definiti come stack1stack2.

Enqueue: Gli elementi euqueued vengono sempre inseriti stack1

Dequeue: La parte superiore di stack2 può essere estratto perché è il primo elemento inserito nella coda quando stack2 non è vuoto. quando stack2 è vuoto, facciamo scoppiare tutti gli elementi da stack1 e spingili dentro stack2 uno per uno. Il primo elemento di una coda viene inserito nella parte inferiore di stack1. Può essere estratto direttamente dopo scoppiare e spingere le operazioni poiché è in cima stack2.

Il seguente è lo stesso codice di esempio 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;
}

Questa soluzione è presa in prestito da il mio blog . Analisi più dettagliate con simulazioni di operazioni passo-passo sono disponibili nella mia pagina web del blog.

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

        }
    }
1
imvp

Implementazione di una coda utilizzando due stack 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()!)
            }
        }
    }
}
1
davejlin

Mentre riceverai molti post relativi all'implementazione di una coda con due stack: 1. O rendendo il processo enQueue molto più costoso 2. O rendendo il processo deQueue molto più costoso

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

Un modo importante che ho scoperto dal post precedente stava costruendo la coda con la sola struttura di dati dello stack e lo stack delle chiamate di ricorsione.

Mentre si può sostenere che letteralmente questo è ancora utilizzando due stack, ma idealmente questo sta usando solo una struttura di dati dello stack.

Di seguito è la spiegazione del problema:

  1. Dichiarare uno stack singolo per enQueuing e deQueing dei dati e Inserire i dati nello stack.

  2. mentre deQueueing ha una condizione di base in cui viene inserito l'elemento dello stack quando la dimensione dello stack è 1. Ciò garantisce che non vi sia overflow dello stack durante la ricorsione deQueue.

  3. Mentre deQueueing pop prima i dati dalla cima della pila. Idealmente questo elemento sarà l'elemento che è presente in cima alla pila. Ora, una volta fatto, richiama ricorsivamente la funzione deQueue e poi spinge l'elemento spuntato in alto nello stack.

Il codice apparirà di seguito:

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;

In questo modo è possibile creare una coda utilizzando una struttura dati a pila singola e lo stack di chiamate di ricorsione.

1
Radioactive

Risponderò a questa domanda in Go perché Go non ha un sacco di raccolte nella sua libreria standard.

Dal momento che uno stack è davvero facile da implementare ho pensato di provare a utilizzare due stack per realizzare una coda a doppio attacco. Per capire meglio come sono arrivato alla mia risposta ho diviso l'implementazione in due parti, la prima parte è probabilmente più facile da capire ma è incompleta.

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

Sono fondamentalmente due stack in cui permettiamo che il fondo degli stack sia manipolato l'uno dall'altro. Ho anche usato le convenzioni di denominazione STL, in cui le tradizionali operazioni Push, pop, peek di uno stack hanno un prefisso fronte/retro che si riferiscono al fronte o al retro della coda.

Il problema con il codice precedente è che non utilizza la memoria in modo molto efficiente. In realtà, cresce all'infinito finché non si esaurisce lo spazio. È davvero brutto. La soluzione per questo è semplicemente riutilizzare il fondo dello spazio di stack quando possibile. Dobbiamo introdurre un offset per tracciare questo dato che una fetta in Go non può crescere nella parte anteriore una volta ridotta.

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

Sono molte piccole funzioni ma delle 6 funzioni 3 sono solo specchi dell'altro.

0
John Leidegren

Di seguito è riportata la soluzione in linguaggio javascript utilizzando la sintassi ES6.

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

Di seguito è l'utilizzo:

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"
0
Jyoti Prasad Pal
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();
    }


}

Per ogni operazione di accodamento, aggiungiamo all'inizio dello stack1. Per ogni dequeue, svuotiamo il contenuto di stack1 in stack2 e rimuoviamo l'elemento in cima allo stack. La complessità temporale è O(n) per dequeue, poiché dobbiamo copiare lo stack1 in stack2. la complessità temporale di un accodamento è la stessa di uno stack regolare

0
PradGar

Con O(1)dequeue(), che è lo stesso di 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()

Con O(1)enqueue() (questo non è menzionato in questo post, quindi questa risposta), che usa anche il backtracking per schiumare e restituire l'elemento più in basso.

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

Ovviamente, è un buon esercizio di codifica in quanto inefficiente ma elegante tuttavia.

0
hIpPy