用俩个栈模拟实现一个队列,如果栈的容量分别是O和P(O>P),那么模拟实现的队列最大容量是多少?

刚才做题碰到了这个有意思的题。
两个栈实现队列是《剑指offer》上的题,大家之前或许都有做过。
这道题有意思在栈的容量是受限的,求的是容量。

这道题应该再深入的思考下,

首先,到底如何用两个栈实现队列。

大家都知道栈是FILO,队列是FIFO。可真正该实现的是时候就不是简简单单的想 着把一个栈里的数据,存入另一个栈中,这样再取出来就是先进的先出了。
关键问题是何时将一个栈中的数据存入另一个栈
栈和队列的关键操作是push()pop(),前者负责压入一个数据,后者负责弹出。还有个top()/front()分别取栈顶/队首元素。那应该如何用俩栈实现队列的push()呢?

class DemoQueue
{
	stack<int> s1, s2;
public:
	void push(int val)
	{
	//	s2.push(val);  直接存入第二个栈等着pop()? 连着存多个push()不就跟stack一样了么,显然不行。
		s1.push(val); 
	// s2.push(val)   每push一次都要更新s2以使pop()能正常pop()? 显然也不行,要知道pop()的关键是要保证s2的top()时刻都是队列的队首 
	}
	//所以其实push只需压入数据给第一个栈就好了。
	void pop()
	{
		//那pop()就需要下功夫,要知道客户有可能在任何时候调用pop()
		if (s1.empty() && s2.empty())
			throw "Wtf";
		//首先,如果s2没有任何数据,那就得从s1调,并且是全调,因为s1的栈底存的是最早进入的数据。
		if (s2.empty())
		{
			while (!s1.empty())
			{
				s2.push(s1.top());
				s1.pop();
			}
		}
		//这时s2栈顶就是队首,我们再想如果s2里本来就有数据呢?那么这个数据其实就是队首!不需要从s1调。
		//也就是说,s2直接pop()就行了。
		s2.pop();
	}
};

其实大家都懂,我真不该费笔墨墨迹这半天。

然后关键是这题它限制了栈是有容量的,而且是求队列的最大容量,我寻思半天选个O+P(亏我还之前实现过,换个思路就懵逼了)。

为什么要选O+P,我以为队列最大的容量就存呗,O存满了再存P,那就是最大了呗。

其实还是这栈与队列的转换原理不够透彻。要知道一个栈存满了是要把这个栈的所有元素转移到另一个栈,再存这个栈的,并且要保证等全push()完后pop()的对,是FIFO

那么有两种存储方式:

1)如果先存容量为P的栈(以下简称P),P存满了把P的数据全压入O,因为O比P大,O是未满的,但是没有办法把它填满了,因为O目前的栈顶就是队首。 所以最大存储量就是2P。
2)如果先存O, 不能直接存满O,因为P<O,存满O,再转入P,P的栈顶不是队首。那就还是存个P,但最大不是2P,因为O第一次存P个数据转入P后,O可以存个P+1个,对你想的没错,O最后剩的那个是队列pop()P次后的队首。

总结:最大存 2P+1

延展思维:

既然栈可能有容量,那么要是用有容量的栈设计队列需要注意哪里呢?
我认为改个push就好啦

stack<int> s1, s2;
int s2MAX_SIZE;//s1比s2容量大
public:
	void push(int val)
	{
		if (s1.size() + s2.size() == 2*s2MAX_SIZE)
		{
			cout << "No push, queue is full";
			return;
		}
		if (s1.size() == s2MAX_SIZE)
		{
			if (!s2.empty())
			{
				cout << "No push, queue is full";
				return;
			}
			while (!s1.empty())
			{
				s2.push(s1.top());
				s1.pop();
			}
		}
		s1.push(val);
	}
发布了26 篇原创文章 · 获赞 6 · 访问量 6461

猜你喜欢

转载自blog.csdn.net/weixin_43975128/article/details/99698532