同様の質問が以前に尋ねられました there ですが、ここでの質問はその逆で、2つのキューをスタックとして使用しています。質問...
標準操作(enqueue
、dequeue
、isempty
、size
)の2つのキューが与えられた場合、標準操作(pop
、Push
、isempty
、size
)。
ソリューションのtwoバージョンがあるはずです。
特定の言語実装よりもアルゴリズムに興味があります。ただし、私がよく知っている言語で表現されたソリューションを歓迎します( Java 、 c# 、 python 、 vb 、- javascript 、 php )。
バージョンA(効率的なプッシュ):
バージョンB(効率的なポップ):
これを行う最も簡単な(そしておそらく唯一の)方法は、新しい要素を空のキューにプッシュし、次に他の要素をデキューし、以前に空のキューに入れることです。この方法では、最新のものが常にキューの先頭にあります。これはバージョンBになります。バージョンAの場合は、最後のキューを除く2番目のキューに要素をデキューすることでプロセスを逆にできます。
ステップ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 | | | | | | | | |
+---+---+---+---+---+ +---+---+---+---+---+
1つのキューでこれを行うことができます。
押す:
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));
}
}
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());
}
}
1つのキューを使用してスタックを実装できますか? 2つのキューを使用できますが、単一のキューを検討する方が効率的です。コードは次のとおりです。
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();
}
}
これは、平均的なケースでO(1)に対して機能する私のソリューションです。 in
とout
の2つのキューがあります。以下の擬似コードを参照してください。
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)
ここに私の答えがあります-「ポップ」は非効率的です。すぐに思い浮かぶすべてのアルゴリズムはNの複雑さを持っているようです。Nはリストのサイズです。「ポップ」で作業するか、「プッシュ」で作業するかを選択します。
リストをトレードバックして4番目のアルゴリズムを使用すると、サイズを計算する必要がなくなるため、ループを作成して空と比較する必要があります。
キューの最後の要素に関する情報はキューのサイズを知ることによってのみ利用可能であり、その要素に到達するためにデータを破棄する必要があるため、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
既に述べたように、1つのキューでこのトリックを行うことはないでしょうか?おそらく実用的ではありませんが、少しスリッカーです。
Push(x):
enqueue(x)
for(queueSize - 1)
enqueue(dequeue())
pop(x):
dequeue()
以下は、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()
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();
}
}
S1とS2を、キューの実装で使用される2つのスタックとします。
struct Stack
{ struct Queue *Q1;
struct Queue *Q2;
}
1つのキューが常に空であることを確認します。
プッシュ操作:空でないキューに要素を挿入します。
Push (struct Stack *S, int data) { if(isEmptyQueue(S->Q1) EnQueue(S->Q2, data); else EnQueue(S->Q1, data); }
時間の複雑さ:O(1)
ポップ操作: n-1要素を他のキューに転送し、ポップ操作を実行するためにキューから最後に削除します。
`
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);
} }
時間の複雑さ:ポップ操作の実行時間はO(n)です。ポップが呼び出されるたびに、1つのキューから他のすべての要素を転送します。
もう1つのソリューションを次に示します。
プッシュの場合:-キュー1に最初の要素を追加します。-2番目の要素を追加する場合など、キュー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;
}'
1つの問題があります。キューの名前を変更する方法がわかりません。
これは、1つのキューを使用し、スタックのような機能を提供する非常にシンプルなソリューションです。
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つを挿入し、それから病棟に挿入してから挿入を削除します。この論理により、最初に最後に来ます。例:キューに1を挿入し、2を挿入しようとしています。2回目に1を削除し、再度挿入して、逆の順序になるようにします。
ありがとうございました。
これは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();
}
}
}
#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);
}
}
1つのキューのみを使用する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