文章目录
前置知识
栈的基本操作
//新建栈
stack<int> st;
//入栈
st.push(666);
//弹出
st.pop(666)
//查看栈顶元素
return st.top();
//查看栈是否为空
if(st.empty())
队列的基本操作
//新建队列
queue<int> q;
//加入元素
q.push(666);
//弹出元素
q.pop();
//瞅一眼队头元素
return q.front();
//瞅一眼队尾元素
return q.back();
//检查是否为空
if(q.empty())
栈与队列的底层实现
提问: 栈与队列是容器(container)吗?
栈和队列是以底层容器完成其所有的工作,对外提供统一的接口,底层容器是可插拔的(也就是说我们可以控制使用哪种容器来实现栈的功能)。
std::stack<int, std::vector<int> > third; // 使用vector为底层容器的栈
std::queue<int, std::list<int>> third; // 定义以list为底层容器的队列
所以STL中栈和队列往往不被归类为容器,而被归类为container adapter(容器适配器)。
STL 中栈和队列默认是用什么容器实现的?
我们常用的SGI STL,如果没有指定底层实现的话,默认是以deque
为缺省情况下栈的底层结构。
232. 用栈实现队列
题目描述
LeetCode链接:https://leetcode.cn/problems/implement-queue-using-stacks/description/
露头栈&辅助栈
思路: 一个stIn
, 一个stOut
push
的时候, 先将stIn
的元素转到stOut
中, 再在stIn中加入目标元素, 再将stOut
的倒回去。
其他时候就可着stIn
薅就完事儿了
class MyQueue {
private:
stack<int> stIn;
stack<int> stOut;
public:
MyQueue() {
}
void push(int x) {
// 先将stIn中的元素倒入stOut
while(!stIn.empty()){
stOut.push(stIn.top());
stIn.pop();
}
// 将x加入stIn
stIn.push(x);
// 将stOut中元素倒回stIn
while(!stOut.empty()){
stIn.push(stOut.top());
stOut.pop();
}
return;
}
int pop() {
int val = stIn.top();
stIn.pop();
return val;
}
int peek() {
return stIn.top();
}
bool empty() {
return stIn.empty();
}
};
优点: 思考起来很简单
缺点: 每次push的时候很复杂
In栈&out栈
上述方法可行, 但是每次push的时候都要来回倒, 很复杂;
以下实现真正的’‘stIn’‘和’‘stOut’':
push
时只需要stIn
进行push
;
pop
和peek
时如果stOut
为空, 就将stIn
中的数据都倒入stOut
, 然后stOut
进行pop
和top
如果stOut
不为空, 那就直接stOut
进行pop
和top
最好将in2out
的功能抽象出来
class MyQueue {
private:
stack<int> stIn;
stack<int> stOut;
public:
MyQueue() {
}
void in2out(){
while(!stIn.empty()){
stOut.push(stIn.top());
stIn.pop();
}
return;
}
void push(int x) {
stIn.push(x);
return;
}
int pop() {
if(stOut.empty()){
in2out();
}
int val = stOut.top();
stOut.pop();
return val;
}
int peek() {
if(stOut.empty()){
in2out();
}
return stOut.top();
}
bool empty() {
return stIn.empty() && stOut.empty();
// 如果二者都空, 则是真的空
}
};
225. 用队列实现栈
题目描述
LeetCode链接:https://leetcode.cn/problems/implement-stack-using-queues/description/
主从队列法
思路: 一个主队列mainQ
, 一个从队列subQ
mainQ
中元素的顺序和栈保持一致
所以pop
top
操作的时候, 直接mainQ
进行pop
和front
即可
push
的时候, 先subQ.push(x)
, 然后将mainQ
中元素加入subQ
, 然后二者交换
class MyStack {
private:
queue<int> mainQ;
queue<int> subQ;
public:
MyStack() {
}
void push(int x) {
subQ.push(x);
while(!mainQ.empty()){
subQ.push(mainQ.front());
mainQ.pop();
}
swap(mainQ, subQ);
return;
}
int pop() {
int val = mainQ.front();
mainQ.pop();
return val;
}
int top() {
return mainQ.front();
}
bool empty() {
return mainQ.empty();
}
};
单个队列实现
其实可以只用一个链表, 但是需要记录其size信息, 比较麻烦, 这里试一试
class MyStack {
private:
queue<int> mainQ;
public:
MyStack() {
}
void push(int x) {
mainQ.push(x);
return;
}
int pop() {
int size=mainQ.size(), val;
for(int i=0; i<size-1; ++i){
val = mainQ.front();
mainQ.pop();
mainQ.push(val);
}
val = mainQ.front();
mainQ.pop();
return val;
}
int top() {
int size=mainQ.size(), val;
for(int i=0; i<size-1; ++i){
val = mainQ.front();
mainQ.pop();
mainQ.push(val);
}
val = mainQ.front();
mainQ.pop();
mainQ.push(val);
return val;
}
bool empty() {
return mainQ.empty();
}
};
总结
对于常用的数据结构, 最好清楚(至少了解)其底层实现, 这样面试官问起来的时候, 不会表现的你只会简单调用.
以及如果能在面试时给出一道题多种解法, 多种思路, 并且阐述其优劣, 肯定是很加分的.
本文参考:
232.用栈实现队列
225. 用队列实现栈