Une question similaire avait été posée plus tôt là , mais la question ici est l'inverse de celle-ci, utilisant deux files d'attente comme une pile. La question...
Étant donné deux files d'attente avec leurs opérations standard (enqueue
, dequeue
, isempty
, size
), implémente une pile avec ses opérations standard (pop
, Push
, isempty
, size
).
Il devrait y avoir deux versions de la solution.
L'algorithme m'intéresse plus que toute implémentation de langage spécifique. Cependant, je me félicite des solutions exprimées dans des langages que je connais bien ( Java , c # , python , vb , - javascript , php ).
Version A (Push efficace):
Version B (pop efficace):
La manière la plus simple (et peut-être la seule) de procéder consiste à insérer de nouveaux éléments dans la file vide, puis à retirer de la file d'attente les autres éléments et à les placer dans la file précédemment vide. De cette façon, le dernier est toujours en tête de la file d'attente. Ce serait la version B, pour la version A, il suffit d'inverser le processus en retirant les éléments de la file d'attente dans la deuxième file d'attente, à l'exception de la dernière.
Étape 0:
"Stack"
+---+---+---+---+---+
| | | | | |
+---+---+---+---+---+
Queue A Queue B
+---+---+---+---+---+ +---+---+---+---+---+
| | | | | | | | | | | |
+---+---+---+---+---+ +---+---+---+---+---+
Étape 1:
"Stack"
+---+---+---+---+---+
| 1 | | | | |
+---+---+---+---+---+
Queue A Queue B
+---+---+---+---+---+ +---+---+---+---+---+
| 1 | | | | | | | | | | |
+---+---+---+---+---+ +---+---+---+---+---+
Étape 2:
"Stack"
+---+---+---+---+---+
| 2 | 1 | | | |
+---+---+---+---+---+
Queue A Queue B
+---+---+---+---+---+ +---+---+---+---+---+
| | | | | | | 2 | 1 | | | |
+---+---+---+---+---+ +---+---+---+---+---+
Étape 3:
"Stack"
+---+---+---+---+---+
| 3 | 2 | 1 | | |
+---+---+---+---+---+
Queue A Queue B
+---+---+---+---+---+ +---+---+---+---+---+
| 3 | 2 | 1 | | | | | | | | |
+---+---+---+---+---+ +---+---+---+---+---+
Nous pouvons le faire avec une file d'attente:
Pousser:
n
est le nombre d'éléments de la file d'attente, supprimez et insérez l'élément n-1
fois.pop:
.
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
+----+----+----+----+----+----+
Exemple de mise en œuvre:
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));
}
}
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());
}
}
Pouvons-nous utiliser une seule file d'attente pour implémenter une pile? Je peux utiliser deux files d'attente, mais considérer une seule file d'attente serait plus efficace. Voici le code:
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();
}
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();
}
}
Voici ma solution qui fonctionne pour O(1) en moyenne. Il y a deux files d'attente: in
et out
. Voir le pseudo-code ci-dessous:
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)
Voici ma réponse - où le "pop" est inefficace. Il semble que tous les algorithmes qui nous viennent immédiatement à l’esprit aient une complexité de N, où N est la taille de la liste: que vous choisissiez de travailler sur le "pop" ou de travailler sur le "push"
L'algorithme où les listes sont échangées et les quatrièmes peut être meilleur, car un calcul de taille n'est pas nécessaire, bien que vous ayez toujours besoin de boucler et de comparer avec des vides.
vous pouvez prouver que cet algorithme ne peut pas être écrit plus vite que N en notant que les informations sur le dernier élément d'une file d'attente sont uniquement disponibles en connaissant la taille de la file d'attente et que vous devez détruire les données pour accéder à cet élément, d'où la 2e file d'attente .
La seule façon de rendre cela plus rapide est de ne pas utiliser les files d'attente en premier lieu.
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
Comme on l'a mentionné, une seule file d'attente ne suffirait-elle pas? C'est probablement moins pratique, mais c'est un peu plus glissant.
Push(x):
enqueue(x)
for(queueSize - 1)
enqueue(dequeue())
pop(x):
dequeue()
Voici un pseudo-code simple, Push is O (n), pop/peek is 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()
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
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();
}
}
Soit S1 et S2 les deux piles à utiliser pour la mise en oeuvre des files d'attente.
struct Stack
{ struct Queue *Q1;
struct Queue *Q2;
}
Nous veillons à ce qu'une file d'attente soit toujours vide.
Opération Push: Quelle que soit la file d'attente qui n'est pas vide, insérez l'élément dans celle-ci.
Push (struct Stack *S, int data) { if(isEmptyQueue(S->Q1) EnQueue(S->Q2, data); else EnQueue(S->Q1, data); }
Complexité temporelle: O (1)
Opération Pop: Transférez n-1 éléments vers une autre file d'attente et supprimez-les en dernier pour effectuer une opération pop.
`
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);
} }
Complexité temporelle: la durée d'exécution de l'opération pop est O(n)) à chaque fois que pop est appelée, nous transférons tous les éléments d'une file d'attente à une autre.
Voici une autre solution:
pour Push: -Ajouter le premier élément de la file 1. -Lorsque vous ajoutez un deuxième élément, etc., commencez par mettre en file d'attente l'élément de la file 2, puis copiez tous les éléments de la file 1 dans la file2. -Pour POP simplement retirer l'élément de la file d'attente depuis que vous avez inséré le dernier élément.
Alors,
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;
}'
Il y a un problème, je ne suis pas capable de comprendre, comment renommer les files d'attente ???
Voici une solution très simple qui utilise une file d’attente et offre des fonctionnalités telles que Stack.
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());
}
}
Donc, dans la classe ci-dessus nommée "CustomStack", je vérifie simplement si la file est vide, si elle est vide, insérez-en une, puis insérez-la et supprimez-la. Par cette logique, le premier viendra en dernier. Exemple: Dans la file d'attente, j'ai inséré 1 et j'essaie maintenant d'insérer 2. Une deuxième fois, supprimez 1 et réinsérez-la pour qu'elle devienne dans l'ordre inverse.
Je vous remercie.
voici le code de travail complet en c #:
Il a été mis en œuvre avec Single Queue,
Pousser:
1. add new element.
2. Remove elements from Queue (totalsize-1) times and add back to the Queue
pop:
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();
}
}
}
#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);
}
}
Code Python utilisant une seule file d'attente
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