废话:要找工作了,面试方面得做些准备了,刷一刷题应该没有坏处的,就从《剑指offer》开始吧。
第2.3.5节提到使用两个栈实现队列,相应的代码也已给出。练习题里有一道使用两个队列实现一个栈的题目,大体思路跟使用栈实现队列差不多,书里也给出了大致的思路。需要注意的一点是,如果每次入栈都选则将元素插入到第一个队列中,出队时先将前n-1个元素移交到第二个队列中,然后返回队列一中剩余的唯一一个元素,再将队列二中的元素又依次移交回队列一中,这样做未免效率过于低下。
事实上这样的思路我们可以看作是一直选用队列一作为栈元素的存储容器,而使用队列二作为一个出队时的辅助工具,这样每次出栈时来回复制元素容器元素的操作,效率确实低下。因为两个队列完全一样的,所以我们完全有理由让两个队列轮流作为栈元素的存储容器,这样每次出栈时,只需将所有前n-1个元素从一个队列移交到另一个队列中,然后返回最后一个元素作为出栈结果,这样始终至少有一个队列是空的,而每次进栈时,只需将进占元素放在那个非空队列的末尾(如果两个队列均为空,则随便放在那个里面都行)。这样减少了一半的复制操作。
如果上面说的不好理解,那还是看代码吧
#include <iostream>
#include <queue>
#include <stdexcept>
using namespace std;
template <typename T>
class CStack{
public:
CStack(void){};
~CStack(void){};
void push(const T& node);
const T& pop();
private:
queue<T> q1;
queue<T> q2;
};
template <typename T>
void CStack<T>::push(const T &node)
{
if(!q1.empty()) //队列1在工作
q1.push(node);
else //队列2在工作
q2.push(node);
}
template <typename T>
const T & CStack<T>::pop()
{
if(!q1.empty()) //当前队列1在工作,将要移交至队列2
{
while(q1.size()>1)
{
q2.push(q1.front());
q1.pop();
}
T &temp=q1.front();
q1.pop();
return temp;
}
else if(!q2.empty()) //当前队列2在工作,将要移交至队列1
{
while(q2.size()>1)
{
q1.push(q2.front());
q2.pop();
}
T &temp=q2.front();
q2.pop();
return temp;
}
else //当前两个队列均为空,即栈空。
throw out_of_range("stack is empty");
}
int main()
{
CStack<int> stack;
stack.push(1);
stack.push(2);
stack.push(3);
try{
cout<<stack.pop()<<endl;
stack.push(4);
cout<<stack.pop()<<endl;
cout<<stack.pop()<<endl;
cout<<stack.pop()<<endl;
cout<<stack.pop()<<endl;
}catch(exception &e)
{
cout<<e.what()<<endl;
}
return 0;
}
运行结果:
3
4
2
1
stack is empty
Process returned 0 (0x0) execution time : 0.002 s
Press ENTER to continue.