8.栈和队列
基础知识
栈:stack,先进后出,只能访问栈顶元素。
接口有入栈push(),出栈pop(),返回栈顶元素top(),返回是否为空empty(),返回大小size()
队列:queue,先进先出,队头和队尾均可访问。
接口有入队尾push(),出队头pop(),返回队头元素front(),返回队尾元素back(),返回是否为空empty(),返回大小size()
225用栈实现队列
题目描述
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push
、pop
、peek
、empty
):
实现 MyQueue
类:
void push(int x)
将元素 x 推到队列的末尾int pop()
从队列的开头移除并返回元素int peek()
返回队列开头的元素boolean empty()
如果队列为空,返回true
;否则,返回false
说明:
- 你 只能 使用标准的栈操作 —— 也就是只有
push to top
,peek/pop from top
,size
, 和is empty
操作是合法的。 - 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
解题思路
按照栈底元素相当于队头元素,栈顶元素相当于队尾元素的原则。
一个栈只能从一端出元素,而队列需要从队头出元素,因此一个栈无法模拟队列,需要用两个栈来操作。
一个栈用作记录入队的元素,一个栈用来记录出队的元素。
对于push,直接将元素push进输入栈即可。
对于pop,由于队列元素先进先出,因此需要将输入栈中的元素按照栈顶-栈底依次压入输出栈,再从输出栈中取栈顶元素即为队头的元素。
对于peek,调用pop函数实现。
对于empty,判断输入栈和输出栈同时为空,才说明队列为空。
代码实现
class MyQueue {
public:
//需要用两个栈才能模拟队列,一个栈用来输入,一个栈用来输出
stack<int>sin;
stack<int>sout;
MyQueue() {
}
void push(int x) {
sin.push(x);
}
int pop() {
if(sout.empty())//只有sout为空时,才倒数据
{
while(!sin.empty())
{
sout.push(sin.top());
sin.pop();
}
}
int res=sout.top();
sout.pop();
return res;
}
int peek() {
int res=this->pop();
sout.push(res);//需要把res再放回去
return res;
}
bool empty() {
return sin.empty()&&sout.empty();
}
};
总结
队列两端开口,栈一端开口,因此用栈来模拟队列时需要用两个栈来实现,一个按照正常的入队顺序入栈a。另一个栈b按照a出栈的顺序将元素放入栈b,就实现了对栈a元素的逆序。这样出栈b顶端的元素就相当于出队头的元素。
225用队列实现栈
题目描述
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push
、top
、pop
和 empty
)。
实现 MyStack
类:
void push(int x)
将元素 x 压入栈顶。int pop()
移除并返回栈顶元素。int top()
返回栈顶元素。boolean empty()
如果栈是空的,返回true
;否则,返回false
。
注意:
- 你只能使用队列的基本操作 —— 也就是
push to back
、peek/pop from front
、size
和is empty
这些操作。 - 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
解题思路
利用一个队列来模拟栈。将队尾视作栈顶,队头视为栈底:
对队列进行push操作,元素加入队尾,就相当于将元素压入栈顶。
对于pop,由于栈和队列元素出的顺序相反,因此比较复杂。好在队列是两端开口,如果想出队尾的元素,只需要将队尾之前的所有元素都出队再重新入队。那么队尾的元素就换到了队头,出队头元素即实现了栈底元素出栈。
对于top,若想返回栈顶元素,只需要返回队尾元素back即可。
对于empty,可以直接对队列进行empty判断。
top
代码实现
class MyStack {
public:
queue <int>q;
MyStack() {
}
void push(int x) {
q.push(x);
}
int pop() {
int size=q.size();
size--;
while(size--)
{
q.push(q.front());//将队头元素放入队尾
q.pop();//队头元素出队
}
int result=q.front();//原队列的最后一个元素
q.pop();
return result;
}
int top() {
return q.back();//队列既可以访问队头,也可以访问队尾
}
bool empty() {
return q.empty();
}
};
总结
对于pop操作,需要记录队头元素,作为返回值。