栈和队列是非常经典的数据结构,基本上是随处可见了。
为什么把这两者放在一起说呢?
因为对于C++的STL来说,这两者都是容器适配器,默认都是以deque为底层实现的。
我们都知道栈是【先进后出】,队列是【先进先出】
使用双端队列deque并且进行一些加工就可以实现栈和队列的效果,这也是STL中栈和队列的实现方式。
具体细节可以看这篇笔记:
【STL源码剖析】总结笔记(7):巧妙的deque
栈和队列互相实现
有一类题目是栈和队列的相互实现,比如用栈实现队列或者用队列实现栈。
虽然没有太明显的实际意义,但是对于理解栈和队列的结构至关重要。
用栈实现队列
用栈实现队列就要思考队列的特点,那些是栈需要调整的。
入队列和入栈一致,不需要修改。
而出队和出栈恰好相反,所以我们需要两个栈来对栈内的数据进行处理。
比如想实现1,2,3入队列然后1出队。
这时候要把1号栈中的[1,2,3]全部出栈,再放入2号栈变为[3,2,1],这时出栈的就是队头。
如果1出队后,变为[2,3],此时[4,5]又入栈了怎么办呢?
这就要看2号栈里是否还有数据,如果有那么还是存在队头的,不需要把新数据倒入。
class MyQueue {
public:
stack<int>stack1;
stack<int>stack2;
MyQueue() {
}
void push(int x) {
stack1.push(x);
}
int pop() {
if(stack2.empty()){
while(!stack1.empty()){
stack2.push(stack1.top());
stack1.pop();
}
}
int res=stack2.top();
stack2.pop();
return res;
}
int peek() {
int res=pop();//直接复用pop()
stack2.push(res);
return res;
}
bool empty() {
return stack1.empty()&&stack2.empty();
}
};
需要注意:
在stack中的pop()会直接把栈顶元素删除,而不会返回值。所以想要实现题目中的pop()需要先记录再pop()
peek()这个地方直接复用了写好的pop()函数,因为需要队列的头元素,所以复用更高效。
用队列实现栈
队列实现栈就要考虑栈的特点和队列有什么差异。
队列入队和栈入栈还是一致的,不需要改动。
出队因为是队头,而栈需要出的元素在队尾,所以需要调整。
这里我们不使用新的空间,直接把前面的元素搬到队尾的后面,再次入队。
比如[1,2,3,4],弹出栈头应该是4,我们把前面的元素重新入队,得到[4,1,2,3],再弹出4即可。
class MyStack {
public:
queue<int>que;
MyStack() {
}
void push(int x) {
que.push(x);
}
int pop() {
int size=que.size();
while(size>1){
que.push(que.front());
que.pop();
size--;
}