Как реализовать очередь, используя два стека?

Я знаю, что немного опаздываю на вечеринку, но для людей, которые также хотят получить __destruct для выполнения, когда возникают CTRL + C и / или фатальные ошибки, вы можете попробовать это (ниже - тестовый пример ):

Index.php

<?php

// Setup CTRL+C and System kill message handler
// The only signal that cannot be caught is the SIGKILL (very hard kill)
declare(ticks = 1); // Required else it won't work.
pcntl_signal(SIGTERM, 'close'); // System kill (Unhappy Termination)
pcntl_signal(SIGINT, 'close'); // CTRL+C (Happy Termination)

// Shutdown functions will be executed even on fatal errors
register_shutdown_function('close');

function close($signal = null) // only pcntl_signal fills $signal so null is required
{
    // Check if there was an fatal error (else code below isn't needed)
    $err = error_get_last();
    if(is_array($err))
    {
        foreach(array_keys($GLOBALS) as $key)
        {
            if(in_array($key, ['_GET', '_POST', '_COOKIE', '_FILES', '_SERVER', '_REQUEST', '_ENV', 'GLOBALS']))
                continue;

            // This will automatically call __destruct
            unset($GLOBALS[$key]);
        }
    }
}

// Example
class blah
{
    private $id = '';

    public function __construct()
    {
        $this->id = uniqid();
        // note this piece of code, doesn't work on windows!
        exec('mkdir /tmp/test_'.$this->id);
    }

    public function __destruct()
    {
        // note this piece of code, doesn't work on windows!
        exec('rm /tmp/test_'.$this->id.' -R');
    }
}

// Test
$a = new blah();
$b = new blah();
$c = new blah();
$d = new blah();
$e = new blah();
$f = new blah();
$g = new blah();
$h = new blah();
$i = new blah();
$j = new blah();
$k = new blah();
$l = new blah();
$m = new blah();
$n = new blah();
$o = new blah();
$p = new blah();
$q = new blah();
$r = new blah();
$s = new blah();
$t = new blah();
$u = new blah();
$v = new blah();
$w = new blah();
$x = new blah();
$y = new blah();
$z = new blah();

// The script that causes an fatal error
require_once(__DIR__.'/test.php');

Test.php

<?php

// this will create a parse (E_PARSE) error.
asdsaddsaadsasd

Примечание: вызывание исключений для исключения или исключения в деструкторах или функции выключения вызовет скрипт для немедленного завершения.

374
задан Levent Divilioglu 23 August 2016 в 00:59
поделиться

19 ответов

Держите 2 стека, назовем их inbox и outbox.

Поставить в очередь :

  • Вставить новый элемент в очередь inbox

:

  • Если outbox пусто, заполните его, вытолкнув каждый элемент из inbox и вставив его в outbox

  • Pop и вернув верхний элемент из 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();
    }

}
677
ответ дан rimsky 23 August 2016 в 00:59
поделиться

Реализация очереди с использованием двух объектов 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();
        }

}
-2
ответ дан realPK 23 August 2016 в 00:59
поделиться
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();
    }


}

Для каждой операции добавления в очередь мы добавляем в начало стека1. Для каждой очереди мы опускаем содержимое стека 1 в стек 2 и удаляем элемент в верхней части стека. Сложность времени O (n) для очереди, так как мы должны скопировать stack1 в stack2. Временная сложность enqueue такая же, как и у обычного стека

-1
ответ дан Matthias 23 August 2016 в 00:59
поделиться

Я отвечу на этот вопрос в 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 имеют префикс front / back независимо от того, ссылаются ли они на начало или конец очереди.

Проблема с приведенным выше кодом заключается в том, что он не очень эффективно использует память. На самом деле, он растет бесконечно, пока вы не исчерпаете пространство. Это действительно плохо. Решением этой проблемы является простое повторное использование нижней части пространства стека, когда это возможно. Мы должны ввести смещение, чтобы отследить это, так как срез в 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 из них являются просто зеркалами другой.

0
ответ дан John Leidegren 23 August 2016 в 00:59
поделиться

Ниже приведено решение на языке JavaScript с использованием синтаксиса 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 };

Ниже приведено использование:

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 23 August 2016 в 00:59
поделиться

Решение в 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 23 August 2016 в 00:59
поделиться

Реализация очереди с использованием двух стеков в 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 23 August 2016 в 00:59
поделиться
// 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 23 August 2016 в 00:59
поделиться

Вам нужно будет вытолкнуть все из первого стека, чтобы получить нижний элемент. Затем поместите их все обратно во второй стек для каждой операции "удаления очереди".

2
ответ дан Witold Kaczurba 23 August 2016 в 00:59
поделиться

Пусть реализуемая очередь - это 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 дорогостоящей)

В этом методе при работе в очереди новый элемент вводится в верхней части стека1. В операции удаления очереди, если стек2 пуст, тогда все элементы перемещаются в стек2 и, наконец, возвращается верхняя часть стека 2.

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) перемещает элементы один раз и перемещает элементы, только если стек2 пуст.

7
ответ дан nevets1219 23 August 2016 в 00:59
поделиться

Время сложностей было бы хуже, хотя. Хорошая реализация очереди делает все в постоянное время.

Редактировать

Не уверен, почему мой ответ был здесь опущен. Если мы программируем, мы заботимся о сложности времени, и использование двух стандартных стеков для создания очереди неэффективно. Это очень актуальный и актуальный момент. Если кто-то еще будет нуждаться в этом, мне было бы интересно узнать почему.

Немного подробнее : почему использование двух стеков хуже, чем просто очереди: если вы используете два стека, и кто-то вызывает dequeue, пока исходящий ящик пуст, вам нужно линейное время, чтобы добраться до нижняя часть почтового ящика (как вы можете видеть в коде Дейва).

Вы можете реализовать очередь в виде односвязного списка (каждый элемент указывает на следующий вставленный элемент), сохраняя дополнительный указатель на последний вставленный элемент для толчков (или делая его циклическим списком). Реализация очереди и очереди для этой структуры данных очень проста в постоянном времени. Это наихудшее постоянное время, не амортизируется. И, как кажется, в комментариях просят дать такое пояснение, постоянное время в худшем случае строго лучше, чем амортизированное постоянное время.

11
ответ дан Tyler 23 August 2016 в 00:59
поделиться

для разработчика c # здесь полная программа:

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 23 August 2016 в 00:59
поделиться

Вы даже можете смоделировать очередь, используя только один стек. Второй (временный) стек может быть смоделирован стеком рекурсивных вызовов метода вставки.

Принцип остается неизменным при добавлении нового элемента в очередь:

  • Вам необходимо перенести элементы из одного стека в другой временный стек, чтобы изменить их порядок.
  • Затем вставьте новый элемент для вставки во временную стопку
  • Затем перенесите элементы обратно в исходную стопку
  • Новый элемент будет в нижней части стек, и самый старый элемент находится сверху (первым должен быть извлечен)

Класс очереди, использующий только один стек, будет выглядеть следующим образом:

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();
    }
}
80
ответ дан pythonquick 23 August 2016 в 00:59
поделиться

Вот мое решение в Java с использованием списка ссылок.

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

}

Примечание: В этом случае операция всплывающего окна занимает очень много времени. Поэтому я не буду предлагать создавать очереди, используя два стека.

0
ответ дан Irshad ck 23 August 2016 в 00:59
поделиться

С O(1) dequeue(), что совпадает с ответом pythonquick :

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

Очевидно, это хорошее упражнение по кодированию, так как оно неэффективно, но, тем не менее, элегантно.

0
ответ дан hIpPy 23 August 2016 в 00:59
поделиться

В то время как вы получите много сообщений, связанных с реализацией очереди с двумя стеками: 1. Либо сделав процесс enQueue намного более дорогостоящим 2. Или сделав процесс deQueue намного более дорогим

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

Один важный способ, который я узнал из вышеприведенного поста, заключался в построении очереди только со структурой данных стека и вызовом рекурсии стек.

Хотя можно утверждать, что буквально это все еще использует два стека, но в идеале это использует только одну структуру данных стека.

Ниже приводится объяснение проблемы:

  1. Объявите один стек для постановки и обработки данных и поместите данные в стек.

  2. в то время как у deQueueing есть базовое условие, когда элемент стека выскакивает, когда размер стека равен 1. Это обеспечит отсутствие переполнения стека во время рекурсии deQueue.

  3. При удалении очереди сначала вытолкнуть данные из верхней части стека. В идеале этот элемент будет элементом, который присутствует в верхней части стека. Теперь, когда это будет сделано, рекурсивно вызовите функцию deQueue, а затем вставьте элемент, расположенный выше, обратно в стек.

Код будет выглядеть следующим образом:

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;

Таким образом, вы можете создать очередь, используя структуру данных с одним стеком и стек вызовов рекурсии.

1
ответ дан Radioactive 23 August 2016 в 00:59
поделиться

A - Как перевернуть стек

Чтобы понять, как построить очередь, используя два стека, вы должны понимать, как полностью перевернуть стек. Помните, как работает стек, это очень похоже на стек блюдо на вашей кухне. Последнее вымытое блюдо будет на вершине чистой стопки, которая называется L ast I n F irst O 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 слева, будет называться Input Stack), другой стек будет использоваться для операции dequeue (стек # 2 справа, будет называться Output Стек). Посмотрите на изображение ниже:

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 [1138]

Тогда что будет, если мы выполним операцию удаления очереди? Всякий раз, когда выполняется операция удаления очереди, очередь будет проверять, является ли стек вывода пустым или нет (см. Псевдокод выше). Если стек вывода пуст, то стек вывода будет извлечен на выходе, чтобы элементы стека ввода будет полностью изменен. Перед возвратом значения состояние очереди будет таким, как показано ниже:

enter image description here

Проверьте порядок элементов в стеке вывода ( Стек № 2). Очевидно, что мы можем вытолкнуть элементы из стека вывода, чтобы вывод был таким же, как если бы мы вышли из очереди. Таким образом, если мы выполним две операции удаления очереди, сначала получим {1, 2} соответственно. Тогда элемент 3 будет единственным элементом выходного стека,

199
ответ дан Levent Divilioglu 23 August 2016 в 00:59
поделиться

Два стека в очереди определены как stack1 и stack2 .

Enqueue: euqueued элементы всегда помещаются в stack1

Dequeue: Верхняя часть 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;
}

Это решение заимствовано из моего блога . Более подробный анализ с пошаговым моделированием работы доступен на моей странице в блоге.

2
ответ дан Andrew Barber 23 August 2016 в 00:59
поделиться

Реализуйте следующие операции стеков использования очереди.

нажатие (x) - элемент Нажатия x к концу очереди.

поп () - Удаляет элемент из перед очередью.

быстрый взгляд () - Получают передний элемент.

пустой () - Возврат, пуста ли очередь.

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();
  }
}
1
ответ дан 22 November 2019 в 23:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: