-
栈和队列理论基础
-
队列是先进先出,栈是先进后出
-
栈和队列是STL里面的两个数据结构
-
三个最为普遍的STL版本
-
1.HP STL其他版本的C++ STL,一般是以HP STL为蓝本实现出来的,HP STL是C++ STL的第一个实现版本,且开放源代码
-
2.P.J.Plauger STL 由P.J.Plauger参照HP STL实现出来的,被Visual C++编译器所采用,不是开源的。
-
3.SGI STL 由Silicon Graphics Computer Systems公司参照HP STL实现,被Linux的C++编译器GCC所采用,SGI STL是开源软件,源码可读性甚高。
-
-
-
栈提供push和pop等等接口,所有元素必须符合先进后出规则,所以栈不提供走访功能,也不能提供迭代器,不像是set或者map提供迭代器来遍历所有元素。栈是以底层容器完成其所有的工作,对外提供统一的接口,底层容器是可插拔的(也就是说我们可以控制使用哪种容器来实现栈的功能)。所以STL中栈往往不被归类为容器,而被归类为container adapter(容器适配器)
-
栈的底层实现可以是vector,deque,list都是可以的,主要就是数组和链表的底层实现。常用的SGI STL,如果没有指定底层实现的化,默认是以deque为缺省情况下栈的底层结构,也可以指定vector为栈的底层实现
-
队列中先进先出的数据结构,同样不允许有遍历行为,不提供迭代器,SGI STL中队列一样是以deque为缺省情况下的底部结构,也可以指定list为其底层实现,所以STL队列也不被归类为容器,而被归类为container adapter(容器适配器)
-
232.用栈实现队列
1.双栈实现队列:在push数据的时候,只要数据放进输入栈就可以,但是在pop的时候,输出站如果为空,就把进栈数据全部导入,再从栈弹出数据,如果输出栈不为空,则直接从出栈弹出数据就可以了
class MyQueue {
public:
stack<int> stIn;
stack<int> stOut;
MyQueue() {
}
// 将元素x推到队列的末尾
void push(int x) {
stIn.push(x);
}
// 从队列的开头移除并返回元素
int pop() {
if(stOut.empty()) {
while(!stIn.empty()) {
stOut.push(stIn.top());
stIn.pop();
}
}
int result = stOut.top();
stOut.pop();
return result;
}
// 返回队列开头的元素
int peek() {
int res = this->pop();
stOut.push(res);
return res;
}
// 判断队列是否为空
bool empty() {
return stIn.empty() && stOut.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();
*/
225.用队列实现栈
1.用两个队列实现:用两个队列que1和que2实现队列的功能,que2其实完全就是一个备份的作用,把que1最后面的元素以外的元素都备份到que2,然后弹出最后面的元素,再把其他元素从que2导回que1
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() {
int size = que1.size();
size--;
while(size--) {// 将que1 导入que2,但要留下最后一个元素
que2.push(que1.front());
que1.pop();
}
int result = que1.front(); // 留下的最后一个元素就是要返回的值
que1.pop();
que1 = que2; // 再将que2赋值给que1
while(!que2.empty()) { // 清空que2
que2.pop();
}
return result;
}
/** Get the top element. */
int top() {
return que1.back();
}
/** 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();
*/
2.一个队列模拟栈:一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外)重新添加到队列尾部,此时在去弹出元素就是栈的顺序了
class MyStack {
public:
queue<int> que;
/** Initialize your data structure here. */
MyStack() {
}
/** Push element x onto stack. */
void push(int x) {
que.push(x);
}
/** Removes the element on top of the stack and returns that element. */
int pop() {
int size = que.size();
size--;
while(size--) {
que.push(que.front());
que.pop();
}
int result = que.front();
que.pop();
return result;
}
/** Get the top element. */
int top() {
return que.back();
}
/** Returns whether the stack is empty. */
bool empty() {
return que.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();
*/
20.有效的括号
-
本题一共有三种情况
-
字符串里左括号多余了
-
字符串没有括号多余,但是出现不匹配的情况
-
字符串右括号多余了
-
1.栈的拿手好戏:如果遇到左括号就在栈里存入对应的右括号,如果匹配的时候发现栈为空或者元素不匹配的情况就直接返回false。最后如果栈不为空的情况,也返回false
class Solution {
public:
bool isValid(string s) {
if(s.size() % 2 != 0) return false;
stack<char> st;
for(int i = 0; i < s.size(); i++) {
if(s[i] == '(') st.push(')');
else if(s[i] == '[') st.push(']');
else if(s[i] == '{') st.push('}');
else if(st.empty() || s[i] != st.top()) return false;
else st.pop();
}
return st.empty();
}
};
1047.删除字符串中的所有相邻重复项
1047. 删除字符串中的所有相邻重复项 - 力扣(LeetCode)
1.栈的拿手好戏:遍历整个字符串,如果栈为空或者元素不匹配,就把元素存入栈中,如果元素匹配,就弹出栈的匹配元素,最后将栈输出,并反转整个结果
class Solution {
public:
string removeDuplicates(string s) {
stack<char> st;
for(int i = 0; i < s.size(); i++) {
if(st.empty() || s[i] != st.top()) {
st.push(s[i]);
} else {
st.pop();
}
}
string result = "";
while(!st.empty()) {
result += st.top();
st.pop();
}
reverse(result.begin(), result.end());
return result;
}
};
150.逆波兰表达式
1.栈的最后表演:和删除字符串中的所有相邻重复项类似:遇到运算符就把栈的头两个元素进行运算然后存入栈中,最后得出结果
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> st;
for(int i = 0; i < tokens.size(); i++) {
if(tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") {
int num1 = st.top();
st.pop();
int num2 = st.top();
st.pop();
if(tokens[i] == "+") st.push(num2 + num1);
if(tokens[i] == "-") st.push(num2 - num1);
if(tokens[i] == "*") st.push(num2 * num1);
if(tokens[i] == "/") st.push(num2 / num1);
} else {
st.push(stoi(tokens[i]));
}
}
int result = st.top();
st.pop();
return result;
}
};