栈与队列理论基础
-
栈:容器适配器
-
栈提供push 和 pop 等等接口,所有元素必须符合先进后出规则,所以栈不提供走访功能,也不提供迭代器(iterator)。
-
栈是以底层容器完成其所有的工作,对外提供统一的接口,底层容器是可插拔的(也就是说我们可以控制使用哪种容器来实现栈(vector,deque,list,默认是deque)的功能)。
-
-
队列:容器适配器
-
队列中先进先出的数据结构,同样不允许有遍历行为,不提供迭代器, SGI STL中队列一样是以deque为缺省情况下的底部结构。
-
用栈实现队列
-
题目:Leetcode232
-
思路:
-
使用两个栈,一个输入栈,一个输出栈。
-
push时,只需将数据压入输入栈,而pop时,首先判断输出栈是否为空,若为空,则将输入栈中的所有数据放进来,再进行弹出数据;若不为空,则直接弹出数据。
-
判断队列为空:如果进栈和出栈都为空的话,说明模拟的队列为空了。
-
-
时间复杂度:push和empty为O(1), pop和peek为O(n)
- 空间复杂度: O(n)
class MyQueue {
public:
stack<int> sIn;
stack<int> sOut;
MyQueue() {
}
void push(int x) {
//数据压入 输入栈
sIn.push(x);
}
int pop() {
//如果 输出栈 不为空,则将 输入栈 中的元素全部压入 输出栈,输入栈中的元素依次弹出
if(sOut.empty()) {
while(!sIn.empty()) {
sOut.push(sIn.top());
sIn.pop();
}
}
//获取 输出栈 的栈顶元素,并弹出
int result = sOut.top();
sOut.pop();
return result;
}
int peek() {
//复用pop代码,因为只是查询,还要把pop出的元素压回
int result = this->pop();
sOut.push(result);
return result;
}
bool empty() {
return sIn.empty() && sOut.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();
*/
用队列实现栈
-
题目:Leetcode225
-
思路:使用一个单向队列即可。一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时再去弹出元素就是栈的顺序了。
-
时间复杂度:pop为O(n),其他为O(1)
- 空间复杂度: O(n)
class MyStack {
public:
queue<int> ds;
MyStack() {
}
void push(int x) {
ds.push(x);
}
int pop() {
//栈 -> a b c |
//队列 -> (a b)c b a ->
int size = ds.size();
size--;
while(size--) { // 将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部
ds.push(ds.front());
ds.pop();
}
int res = ds.front();
ds.pop();
return res;
}
int top() {
int res = ds.back();
return res;
}
bool empty() {
return ds.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();
*/
总结
学会代码复用,不要惯性思维。