剑指Offer_面试题07_用两个栈实现队列

63 篇文章 1 订阅
40 篇文章 0 订阅

题目:用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

//队列声明如下
template <typename T> class CQueue
{
public:
	CQueue(void) {}
	~CQueue(void) {}

	void push(const T& node);
	T pop();
	void printEmu();

private:
	stack<T> stack1;
	stack<T> stack2;
};

解析:众所周知栈的特性是后进先出,队列的特性先进先出。要想用栈实现队列,必须有两个栈进行。例如把1,2,3存入CQueue队列,将他们按顺序压入stack1,此时stack1是:

3
2
1

栈顶元素为c,若进行出队列操作,应该出队1,但是1在栈底,顺序刚好相反。将stack1中的栈顶依次压入stack2,顺序就会发生该变,此时取stack2的栈顶即为队列队首:
  1
 2
 3

   
 2
 3

我之前的想法是取完队首再将stack2全部压入stack1,维持原始的状态:

   
3 
2 


关键地方之前我一直认为,取完队首元素后,stack2中的元素应该全部压入stack1,维持每次一致的状态,即stack1逆序存储队列元素,stack2为空用于辅助pop操作。后来看了书和网上教程之后,发现我的这种想法做法实际效果不是特别好,虽然完全满足需求,但是空间利用率仅为正确解法的一半。
正确的做法应该是:
1.入队永远是压入stack1;
2.取队首元素的时候,将stack1元素压入stack2后,取完元素,就不再将元素压回stack1。换句话说,若stack2不为空那么它是跟队列头顺序一致,且stack2栈顶就是当前队列的队首,若要出队只要stack2出栈即可。当stack2为空的时候才把stack1全部压入stack2,取栈顶即队首。这样不止可以用stack1保存元素,stack2也可以存储,并且减少了存取操作,可谓一举两得。

两个栈都存在元素的情况:

3
2
1

pop():
  1
 2
 3

   
 2
 3

push(4):
  
 2
43

push(5):
  
52
43

pop():
    
 5 
43

pop():
    
 5 
4 

pop():
    
 5 
4 

   
 4
 5

   
  
 5

代码:
#include <stack>
#include <iostream>
#include <deque>
using namespace std;
//队列声明如下
template <typename T> class CQueue
{
public:
	CQueue(void) {}
	~CQueue(void) {}

	void push(const T& node);
	T pop();
	void printEmu();

private:
	stack<T> stack1;
	stack<T> stack2;
};

template <typename T> 
void CQueue<T>::push(const T& node)
{
	stack1.push(node);
}

/*不完美做法
template <typename T>
T CQueue<T>::pop()
{
	while (!stack1.empty())
	{
		stack2.push(stack1.top());
		stack1.pop();
	}
	T temp = stack2.top();
	stack2.pop();
	while (!stack2.empty())
	{
		stack1.push(stack2.top());
		stack2.pop();
	}
	return temp;
}
*/

//完美做法
template <typename T>
T CQueue<T>::pop()
{
	//如果stack2为空,说明只有stack1保存元素且为逆序
	if (stack2.empty())
	{
		//将stack1全部压入stack2,使改变顺序
		while (!stack1.empty())
		{
			stack2.push(stack1.top());
			stack1.pop();
		}
	}
	//无论如何,此时stack2栈顶即队首
	T res = stack2.top();
	stack2.pop();
	return res;
}

//顺序输出队列元素,用于测试,可能会改变原队列存储结构,内容不变
template <typename T>
void CQueue<T>::printEmu()
{
	if (stack1.empty() && stack2.empty())
	{
		cout << "空队列" << endl;
		return;
	}
	deque<T> record;
	//stack2不为空优先输出stack2
	while(!stack2.empty())
	{
		cout << stack2.top() << " ";
		record.push_back(stack2.top());
		stack2.pop();
	}
	while (!stack1.empty())
	{
		stack2.push(stack1.top());
		stack1.pop();
	}
	while (!stack2.empty())
	{
		cout << stack2.top() << " ";
		record.push_back(stack2.top());
		stack2.pop();
	}
	cout << endl;
	//输出结束后将队列元素重新入队
	while (!record.empty())
	{
		stack1.push(record.front());
		record.pop_front();
	}
}

//测试
int main()
{
	CQueue<int> myQue;
	for (int i = 0; i < 10; ++i)
	{
		myQue.push(i);
	}
	myQue.printEmu();
	myQue.pop();
	myQue.printEmu();
	system("pause");
	return 0;
}


值得一提的是,在STL中,栈stack使用双端队列deque实现的,这道题有点逆流而上的幽默感。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值