二刷 栈与队列

栈和队列是STL(C++标准库)里面的两个数据结构

栈提供push和pop等接口,所有元素必须符合先进后出规则,所以栈不提供走访功能,也不提供迭代器(iterator)。不像是set或者map提供迭代器iterator来遍历所有元素。

栈是以底层容器完成其所有的工作,对外提供统一的接口,底层容器是可插拔的(可以控制使用哪种容器来实现栈的功能)。

STL中栈往往不被归类为容器,而被归类为container adapter(容器适配器)。

STL中栈是用什么容器实现的?

栈的底层实现可以是vector,deque,list都是可以的,主要就是数组和链表的底层实现。

我们常用的SGI STL,如果没有指定底层实现的话,默认是以deque为缺省情况下栈的底层结构。

deque是一个双向队列,只要封住一段,只开通另一端就可以实现栈的逻辑了。

SGI STL中 队列底层实现缺省情况下一样使用deque实现的。

也可以指定vector为栈的底层实现,初始化语句如下:

std::stack<int,std::vector<int>> third;//使用vector为底层容器的栈

队列也是一样的,先进先出的数据结构,同样不允许有遍历行为,不提供迭代器,SGI STL中队列一样是以deque为缺省情况下的底部结构。

也可以指定list为起底层实现,初始化queue的语句如下:

std::queue<int, std::list<int>>third;//定义以list为底层容器的队列

所以STL 队列也不被归类为容器,而被归类为container adapter(容器适配器)


 232. 用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

注意:

1.栈为空才能入栈,栈不为空才能出栈

2.栈先获取top元素,再pop弹出

class MyQueue {
public:
    //设置两个栈
    stack<int> stIn;
    stack<int> stOut;
    MyQueue() {

    }
    
    void push(int x) {
        //直接入栈
        stIn.push(x);
    }
    
    int pop() {
        //只有stOut为空,才能入栈
        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();//直接使用已有的pop函数
        stOut.push(res);//因为pop()弹出了res,所以再添加回去
        return res;
    }
    
    bool empty() {
        return stIn.empty() && stOut.empty();
    }
};

225. 用队列实现栈

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppop 和 empty)。

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。
  • int pop() 移除并返回栈顶元素。
  • int top() 返回栈顶元素。
  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

主要是pop()

1.记录size,保留que1一个元素,在它前面的所有元素移动到que2

2.result获取que1这个元素,弹出

3.que1=que2,清空que2

class MyStack {
public:
    //定义两个队列
    queue<int> que1;
    queue<int> que2;
    MyStack() {

    }
    
    void push(int x) {
        que1.push(x);
    }
    
    int pop() {
        //que1保留一个元素,将在这个元素前面的其他元素全部移动到que2
        //结果获取这个元素,que1弹出
        //que1=que2,清空que2
        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();
    }
};

20.有效的括号

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

三种情况:

1.遍历字符串匹配的过程中,栈已经空了,没有匹配的字符了

2.遍历字符串匹配的过程中,不相符

3.遍历完成后,还有剩余

技巧:遇到([{,入栈右括号,直接用右括号进行匹配即可。

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();//st.top()和s[i]相等,弹出元素
        }
        //遍历完成后,如果还有剩余就不是空,说明返回false
        return st.empty();
    }
};

1047. 删除字符串中的所有相邻重复项

给出由小写字母组成的字符串 S重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

遍历字符串,如果栈为空或者字符和栈顶元素不相等,入栈;否则,重复则弹出;

弹出并收集栈中所有字符,翻转;

class Solution {
public:
    string removeDuplicates(string s) {
        //遍历字符串,如果为空或者字符和栈中不相等,入栈;否则相等,弹出
        //遍历完成后,弹出栈中内容,并翻转
        stack<char> st;
        for (char s : s) {
            if (st.empty() || s != st.top()) {
                st.push(s);
            }else {
                st.pop();
            }
        }

        string result = "";
        while(! st.empty()) {
            result += st.top();
            st.pop();
        }

        reverse (result.begin(), result.end());
        return result;
    }
};

150. 逆波兰表达式求值

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+''-''*' 和 '/' 。
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断 。
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

遇到数字入栈,遇到运算符取栈顶两元素计算,计算结果入栈。

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        //遇到数字入栈,遇到运算符取栈顶两元素计算,计算结果入栈
        stack<long long> st;
        for (int i = 0; i < tokens.size(); i++) {
            if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") {
                //取栈顶两元素
                long long num1 = st.top();
                st.pop();
                long long 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(stoll(tokens[i]));
            }
        }
            char result = st.top();
            st.pop();
            return result;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值