用两个栈实现一个队列主要需要实现的是队列的入队和出队操作。针对这一问题有以下几种方案
方案一
用一个栈来维护队列的出队,入队操作,具体实现方法如下:
入队:将元素压入第一个栈中
出队:
(1)将第一个栈中的元素(除栈底元素外)依次导入第二个栈中
(2)将第一个栈中剩下的那个元素弹出
(3)将第二个栈中的元素依次倒回到第一个栈中
方案二
第一个栈管理队列的入队,第二个栈管理队列的出队操作
和方案一不同的是,步骤(2)后,不需要执行步骤(3),只有当要执行入队操作时,才执行步骤(3)
比较:
方案二比方案一好的一点是不需要每次执行完出队操作后,都将第二个栈中的元素倒回到第一个栈中,因为不是每次都需要入队操作,可以节省时间。
方案三
两个栈共同维护栈的入队出队操作,第一个栈执行入队出队操作,第二个栈执行出队操作
入队:将元素压入第一个栈中(第一个栈中栈顶元素一定是队列的队尾元素,是队列中最后一个进入队列中的元素)
出队:
(1)判断两个栈是否都为空,若都为空,则结束程序,若有一个栈不为空,则执行一下步骤
(2)若第二个栈不为空,则将第二个栈中栈顶元素弹出(因为第二个栈的栈顶元素是队列中最先进入队列中的元素,相当于对头的元素,出队时将队头元素出队)
(3)若第二个栈为空,那么将第一个栈中的元素(除栈底元素)依次导入第二个栈中,删除第一个栈中的元素
方案三代码:
两个栈实现一个队列
template<class T>
class Queue
{
public:
void Push(const T& d)
{
sPush.push(d);
}
void Pop()
{
if (Size())//若两个栈都为空
{
return;
}
if (sPop.empty()) //若第二个栈为空
{
ExChange(sPush, sPop);//将第一个栈中元素导入到第二个栈中
}
sPop.pop();//栈顶元素弹出
}
T& Front()
{
assert(Size());
if (sPop.empty())
{
ExChange(sPush, sPop);
}
return sPop.top();
}
T& Back()
{
assert(Size());
if (sPush.empty())
{
ExChange(sPop, sPush);
}
return sPush.top();
}
bool Empty()
{
return Size()==0;
}
size_t Size()
{
return sPush.size() + sPop.size();
}
private:
//这里是将所有元素都导入第二个栈中后在弹出第二个栈的栈顶元素
void ExChange(stack<T>& sout, stack<T>& sin)//将第一个栈中元素导入到第二个栈中
{
while (!sout.empty())//若第一个栈不为空
{
sin.push(sout.top());//第一个栈中元素依次导入第二个栈中
sout.pop();//弹出该元素
}
}
private:
stack<T> sPush;
stack<T> sPop;
};
测试代码:
void TestQueue()
{
Queue<int> q;
q.Push(1);
q.Push(2);
q.Push(3);
q.Push(4);
q.Push(5);
cout <<q.Size() << endl;
while (!q.Empty())
{
cout <<q.Front() << " ";
q.Pop();
}
}