- 问题描述
用两个栈来实现一个队列,队列的声明如下,实现其中的两个函数,分别完成在队列尾部插入节点和在队列头部删除节点的操作。
声明:
template <typename T> class CQueue
{
public:
CQueue(void);
~CQueue(void);
void appendTail(const T& element)
T deleteHead();
privite:
stack <T> stack1;
stack <T> stack2;
}
其中appendTail函数是队列尾部插入节点函数,deleteHead是删除队列头部节点函数。
- 问题分析
众所周知栈是一种先进后出的结构,而队列是先进先出的。如果我们需要使用两个FILO的结构实现FIFO,不妨这么思考:
分别给两个栈编号,叫做stack1和stack2.我们插入数据时,先将数据都按顺序给stack1里压栈。比如我传入的数据是1,2,3,按照 队列来说输出也应该是1,2,3.我们先将1,2,3压入stack1,那么此时stack1从栈底到栈顶分别为1,2,3.接着,我们将stack1全部出栈,并且每出一个就向stack2压栈。完成这步操作之后,stack2中的数据从栈底到栈顶就是3,2,1了。此时对stack2进行出栈操作,顺序就和队列的完全一样了。
那么,如果我们现在已经将stack1中的数据全部压栈进入stack2了,这时又插入了一个数据,该怎么处理呢?
我们只需将新插入的数据压入stack1,并且只要stack2非空的话,stack1就不用向stack2压栈。这样就保证了即使新插入数据,也不会对模拟队列造成影响。
对于题中要求的两个函数:首先第一个要求在队列尾插入数据。我们经过上面的分析相信你也体会到了,其实stack1就是我们模拟队列的队尾。只不过“队尾”中的节点需要出栈再压入stack2才能用于出队。所以具体实现只需要stack1.push(element)。
第二个问题:先判断stack2是否空,为空的话就从stack1中拿节点压栈。如果stack1也为空的话,队列就是真正的空队,无法进行pop操作了。否则,定义一个T类型的变量,记录stack2.top()用于返回,然后stack2调用一次pop函数即可。
具体代码:
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;
}