理论基础
了解一下 栈与队列的内部实现机智,文中是以C++为例讲解的。
文章讲解:代码随想录
栈和队列是STL(C++标准库)里面的两个数据结构。
三个最为普遍的STL版本:
-
HP STL:其他版本的C++ STL,一般是以HP STL为蓝本实现出来的,HP STL是C++ STL的第一个实现版本,而且开放源代码。
-
P.J.Plauger STL:由P.J.Plauger参照HP STL实现出来的,被Visual C++编译器所采用,不是开源的。
-
SGI STL: 由Silicon Graphics Computer Systems公司参照HP STL实现,被Linux的C++编译器GCC所采用,SGI STL是开源软件,源码可读性甚高。
接下来介绍SGI STL的栈和队列——
栈和队列提供push 和 pop 等等接口,所有元素必须符合先进后出规则,所以它们不提供走访功能,也不提供迭代器(iterator)。 不像是set 或者map 提供迭代器iterator来遍历所有元素。
栈和队列是以底层容器完成其所有的工作,对外提供统一的接口,底层容器是可插拔的(也就是说我们可以控制使用哪种容器来实现栈的功能)。
所以STL中栈和队列往往不被归类为容器,而被归类为container adapter(容器适配器)。
栈和队列的底层实现可以是vector,deque,list, 主要就是数组和链表的底层实现。我们常用的SGI STL,如果没有指定底层实现的话,默认是以deque(deque是一个双向队列,只要封住一段,只开通另一端就可以实现栈的逻辑了)为缺省情况下栈和队列的底层结构。
但可以指定——
std::stack<int, std::vector<int> > third; // 使用vector为底层容器的栈
std::queue<int, std::list<int>> third; // 定义以list为底层容器的队列
232.用栈实现队列
大家可以先看视频,了解一下模拟的过程,然后写代码会轻松很多。
题目链接/文章讲解/视频讲解:代码随想录
这里文章使用的是stIn按栈的顺序存储,stOut按队列的顺序存储,这样不需要老是倒腾,注意这两个栈存储的元素总和才是全部元素。
来了一个元素,就让它存储在stIn里面;如果要pop元素,那就先紧着stOut来pop,如果为空,那就把stIn里面的元素倒腾到stOut里面再pop;要取队列头部元素,就先使用之前写的pop得到元素,然后再push回去,注意必须要调用stOut的push,因为你从哪里拿的就要放到什么位置,stOut的栈顶存储的永远是整个队列的第一个元素,空了才考虑stIn的栈底元素;判断为空否因而要判断两个栈都是否为空。
class MyQueue {
public:
stack<int> stIn;
stack<int> stOut;
MyQueue() {
}
void push(int x) {
stIn.push(x);
}
int pop() {
if(stOut.empty()){
while(!stIn.empty()){
stOut.push(stIn.top());
stIn.pop();
}
}
int tmp=stOut.top();
stOut.pop();
return tmp;
}
int peek() {
int tmp=this->pop();
stOut.push(tmp);
return tmp;
}
bool empty() {
return stIn.empty()&&stOut.empty();
}
};
225. 用队列实现栈
可以大家惯性思维,以为还要两个队列来模拟栈,其实只用一个队列就可以模拟栈了。 建议大家掌握一个队列的方法,更简单一些,可以先看视频讲解。
题目链接/文章讲解/视频讲解:代码随想录
个人感觉使用一个队列更简单更容易懂,使用两个队列就是以一个队列为主,另一个为辅,只有pop的时候才用得到,主要就是把主队列pop剩一个元素,同时push到辅队列里面,得到top后pop掉,然后直接让主队列等于辅队列,再把辅队列清空即可。
使用两个队列——
class MyStack {
public:
queue<int> que1;
queue<int> que2;
MyStack() {
}
void push(int x) {
que1.push(x);
}
int pop() {
int size=que1.size();
while(--size>0){
que2.push(que1.front());
que1.pop();
}
int tmp=que1.front();
que1.pop();
que1=que2;
while(!que2.empty()){
que2.pop();
}
return tmp;
}
int top() {
int tmp=que1.back();
return tmp;
}
bool empty() {
return que1.empty();
}
};
使用一个队列——
class MyStack {
public:
queue<int> que;
MyStack() {
}
void push(int x) {
que.push(x);
}
int pop() {
int size=que.size();
while(--size>0){
int tmp=que.front();
que.pop();
que.push(tmp);
}
int tmp=que.front();
que.pop();
return tmp;
}
int top() {
int tmp=que.back();
return tmp;
}
bool empty() {
return que.empty();
}
};
总结
一些常用的库函数——
stack:
stack<int> st;
st.push(1);
st.push(2);
// st: 1 2
st.top(); // 2
st.size(); // 2
st.pop(); // st: 1
st.empty(); // false
queue:
queue<int> que;
que.push(1);
que.push(2);
// que: 1 2
que.front(); // =1
que.back(); // =2
que.size(); // 2
que.pop(); // que: 2
que.empty(); // false
本文介绍了C++STL中栈和队列的数据结构,包括它们在不同版本STL中的实现(如HPSTL、P.J.PlaugerSTL和SGISTL),以及如何使用栈模拟队列和队列模拟栈的示例代码。作者强调了SGISTL中栈和队列的底层容器灵活性和适配器角色。

699

被折叠的 条评论
为什么被折叠?



