Реализация стека с использованием двух очередей - PullRequest
134 голосов
/ 27 марта 2009

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

Учитывая две очереди со своими стандартными операциями (enqueue, dequeue, isempty, size), реализовать стек со своими стандартными операциями (pop, push, isempty, size).

Должно быть двух версий решения.

  • Версия A : стек должен быть эффективен при нажатии на предмет; и
  • Версия B : стек должен быть эффективен при вытягивании предмета.

Мне интересен алгоритм больше, чем какой-либо конкретной языковой реализации. Тем не менее, я приветствую решения, выраженные на знакомых мне языках (, , , , ).

Ответы [ 21 ]

189 голосов
/ 27 марта 2009

Версия A (эффективный толчок):

  • кнопка:
    • поставить в очередь1
  • поп:
    • , в то время как размер очереди1 больше чем 1, элементы из очереди1 отправляются в очередь2 в очередь2
    • снять очередь и вернуть последний элемент queue1, затем переключить имена queue1 и queue2

Версия B (эффективная популярность):

  • кнопка:
    • поставить в очередь2
    • поставить в очередь все элементы queue1 в queue2, затем переключить имена queue1 и queue2
  • поп:
    • запрос из очереди1
67 голосов
/ 27 марта 2009

Самый простой (и, может быть, единственный) способ сделать это - поместить новые элементы в пустую очередь, а затем удалить из очереди другой и включить в ранее пустую очередь. Таким образом, последние всегда находятся в начале очереди. Это будет версия 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 |   |   |  |   |   |   |   |   |
+---+---+---+---+---+  +---+---+---+---+---+
50 голосов
/ 06 сентября 2011

Мы можем сделать это с одной очередью:

кнопка:

  1. поставить новый элемент в очередь.
  2. Если n - это количество элементов в очереди, то удалите и вставьте элемент n-1 раз.

поп:

  1. Dequeue

.

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));
  }
}
9 голосов
/ 01 декабря 2010
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());
    }
}
4 голосов
/ 12 апреля 2011

Можем ли мы использовать одну очередь для реализации стека? Я могу использовать две очереди, но рассмотрение одной очереди будет более эффективным. Вот код:

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

    }
3 голосов
/ 10 января 2011
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();
   }
}
2 голосов
/ 27 марта 2009

Вот мой ответ - где «поп» неэффективно. Кажется, что все алгоритмы, которые приходят сразу в голову, имеют сложность N, где N - размер списка: выбираете ли вы работать над «поп» или «нажимать»

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

Вы можете доказать, что этот алгоритм не может быть написан быстрее, чем N, отметив, что информация о последнем элементе в очереди доступна только через знание размера очереди, и что вы должны уничтожить данные, чтобы добраться до этого элемента, следовательно 2-я очередь.

Единственный способ сделать это быстрее - это вообще не использовать очереди.

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
2 голосов
/ 21 февраля 2013

Вот мое решение, которое работает для O (1) в среднем случае. Есть две очереди: in и out. Смотрите псевдокод ниже:

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)
1 голос
/ 04 января 2011

Как уже упоминалось, разве одна очередь не сработает? Это, вероятно, менее практично, но немного приятнее.

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

pop(x):
dequeue()
1 голос
/ 30 октября 2013

Вот простой псевдокод, 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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...