1 栈和队列
栈: 后进先出的数据结构
队列:先进先出的数据结构
如图所示:
那么以C++为例,自己使用的编程语言里栈和队列是什么样的呢。可以思考以下几个方面:
- C++中的 stack 是容器吗?
- 我们使用的stack是属于哪个版本的 STL ?
- 我们使用STL中的 stack 是怎么实现的呢?
- stack 提供迭代器来遍历 stack 空间吗?
C++标准库是有多个版本的,要知道我们使用的 STL 是哪个版本的,才能知道对应的栈和队列的实现原理,我们> 使用的是SGI STL,是由Silicon Graphics Computer Systems公司参照HP STL实现,被Linux的C++编译器GCC所采用,SGI STL是开源软件,源码可读性很高。
来说一说栈
- 栈提供push 和 pop 等等接口,所有元素必须符合先进后出规则,所以栈不提供遍历功能,也不提供迭代器(iterator)。不像是set 或者map 提供迭代器iterator来遍历所有元素。
- 栈是以底层容器完成所有的工作,对外提供统一的接口,底层容器是可插拔的-------我们可以控制使用哪种容器来实现栈的功能。所以STL中栈不被归类为容器,而是容器适配器(配接器)container adapter.
那么STL中的栈是用什么容器实现的呢?
从下图中可以看出,栈的内部结构,栈的底层实现可以是vector,deque,list 都是可以的, 主要就是数组和链表的底层实现
我们常用的SGI STL,如果没有指定底层实现的话,默认是以deque为缺省情况下栈的低层结构。deque是一个双向队列,只要封住一段,只开通另一端就可以实现栈的逻辑了。
栈说明白后,队列就比较好理解了?
队列 先进先出的数据结构,同样不允许有遍历行为,不提供迭代器, SGI STL中队列一样是以deque为缺省情况下的底部结构。
所以STL中队列也不被归类为容器,而被归类为container adapter( 容器适配器)。
3 用栈实现队列
https://leetcode-cn.com/problems/implement-queue-using-stacks/
3.1 思路分析
使用栈来模式队列的行为,如果仅仅用一个栈,是一定不行的,所以需要两个栈一个输入栈,一个输出栈,这里要注意输入栈和输出栈的关系。
下面引用大佬的动图,https://mp.weixin.qq.com/s/P6tupDwRFi6Ay-L7DT4NVg
3.2 代码实现
class MyQueue {
//用两个栈实现队列
public:
stack<int> stackIn;
stack<int> stackOut;
/** Initialize your data structure here. */
MyQueue() {
}
/** Push element x to the back of queue. */
void push(int x) {
stackIn.push(x);
}
/** Removes the element from in front of queue and returns that element. */
int pop() {
//当stackOut中是空的时候把stackIn中的数据导入到stackOut中
if (stackOut.empty()) {
//把stackIn中的数据导入,直到其为空为止
while (!stackIn.empty()) {
stackOut.push(stackIn.top());
stackIn.pop();
}
}
int result = stackOut.top();
stackOut.pop();
return result;
}
/** Get the front element. */
int peek() {
int ret = this->pop();
stackOut.push(ret);
return ret;
}
/** Returns whether the queue is empty. */
bool empty() {
return stackIn.empty() && stackOut.empty();
}
};
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue* obj = new MyQueue();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->peek();
* bool param_4 = obj->empty();
*/
4 用队列实现栈
https://leetcode-cn.com/problems/implement-stack-using-queues/
4.1 思路分析
上面做了用栈实现队列,一个输入栈,一个输出栈,那么用队列实现栈也可以这样吗,其实是不行的,队列遵循先入先出的规则,把把一个队列中的数据导入另一个队列中,数据的顺序并没有变,并有变成先进后出的顺序。
所以用队列实现栈的思路可以是:两个队列一个队列是用作备份的作用的。用两个队列que1和que2实现队列的功能,que2其实完全就是一个备份的作用,把que1最后面的元素以外的元素都备份到que2,然后弹出最后面的元素,再把其他元素从que2导回que1。
引用大佬的动图:https://mp.weixin.qq.com/s/yzn6ktUlL-vRG3-m5a8_Yw
4.2 代码实现
class MyStack {
public:
//用两个队列实现栈的功能----后进先出
queue<int> que1;
queue<int> que2;//用于临时备份数据
/** Initialize your data structure here. */
MyStack() {
}
/** Push element x onto stack. */
void push(int x) {
que1.push(x);
}
/** Removes the element on top of the stack and returns that element. */
int pop() {
//将que1中的数据放入到que2中,直到que1中只剩1个数据
while (que1.size() > 1) {
que2.push(que1.front());
que1.pop();
}
//此时que1中有一个数据
int ret = que1.front();
que1.pop();
//把que2中的数据放回que1中
while(!que2.empty()) {
que1.push(que2.front());
que2.pop();
}
return ret;
}
/** Get the top element. */
int top() {
return que1.back();//back:队列尾 front:队列头
}
/** Returns whether the stack is empty. */
bool empty() {
return que1.empty();
}
};
/**
* Your MyStack object will be instantiated and called as such:
* MyStack* obj = new MyStack();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->top();
* bool param_4 = obj->empty();
*/