1、栈和队列理论基础
栈和队列是STL(C++标准库)里面的两个数据结构。
栈:先进后出
栈提供push 和 pop 等等接口,所有元素必须符合先进后出规则,所以栈不提供走访功能,也不提供迭代器(iterator)。 不像是set 或者map 提供迭代器iterator来遍历所有元素。
栈是以底层容器完成其所有的工作,对外提供统一的接口,底层容器是可插拔的(也就是说我们可以控制使用哪种容器来实现栈的功能)
所以STL中栈往往不被归类为容器,而被归类为container adapter(容器适配器)
队列:先进先出的数据结构,同样不允许有遍历行为,不提供迭代器, SGI STL中队列一样是以deque为缺省情况下的底部结构。
也可以指定list 为起底层实现,初始化queue的语句如下:
std::queue<int, std::list> third; // 定义以list为底层容器的队列
所以STL 队列也不被归类为容器,而被归类为container adapter( 容器适配器)。
2、用栈实现队列
class MyQueue {
public:
stack<int> stIn;
stack<int> stOut;
MyQueue() {
}
void push(int x) {
stIn.push(x);
}
int pop() {
if(stOut.empty()){
while(!stOut.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();
}
};
if (stOut.empty())
是C++中的条件判断语句的写法,用于检查 stOut 这个栈(std::stack)是否为空。
这里,stOut 是一个 std::stack 类型的对象,它是C++标准模板库(STL)中的一个容器适配器,提供了后进先出(LIFO)的数据结构。std::stack 提供了多种成员函数来操作栈,其中 empty() 是其成员函数之一。
empty() 成员函数的作用是检查栈是否为空。如果栈为空(即不包含任何元素),则 empty() 函数返回 true;如果栈不为空(即包含至少一个元素),则返回 false。
因此,if (stOut.empty()) 这行代码的意思是:“如果 stOut 栈为空,则执行接下来的代码块(即 if 语句的大括号 {} 中的代码)”。
stIn.top() 调用stIn栈的top()成员函数。top()函数返回栈顶元素的引用(但不移除该元素)。如果stIn不为空,则stIn.top()将返回栈顶元素的值或引用。
stOut.push(…) 调用stOut栈的push()成员函数。push()函数接受一个参数(即要添加到栈顶的元素),并将其压入栈中。
stIn.pop(); 用于移除栈顶的元素
这通常是在你已经使用 stIn.top() 访问了栈顶元素的值之后进行的,以避免内存泄漏或重复处理相同的元素。
3、用队列实现栈
class MyStack {
public:
queue<int> que1;
queue<int> que2;
MyStack()
{
}
void push(int x)
{
que1.push(x);
}
int pop()
{
int size = que1.size();
size--;
while(size--)
{
que2.push(que1.front());
que1.pop();
}
int result = que1.front();
que1.pop();
que1 = que2;
while(!que2.empty())
{
que2.pop();
}
return result;
}
int top()
{
return que1.back();
}
bool empty()
{
return que1.empty();
}
};
优化后采用一个队列来操作
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();
}
};
4、有效的括号
第一种情况:已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false
第二种情况:遍历字符串匹配的过程中,发现栈里没有要匹配的字符。所以return false
第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号return 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() || st.top() != s[i]) return false;
else st.pop();
}
return st.empty();
}
};
else if (st.empty() || st.top() != s[i]) return false;
此处要先判断栈是否为空,如果先调取当前栈栈顶元素,如果为空,相当于操作了空栈,则会异常。
else st.pop(); 这个相当于对对碰消除。
如果遍历完还不为空,相当于左括号多了
5、删除字符串中的所有相邻重复项
class Solution {
public:
string removeDuplicates(string S)
{
string result;
for(char s:S)
{
if(result.empty() || result.back() != s)
{
result.push_back(s);
}else
{
result.pop_back();
}
}
return result;
}
};