恋上数据结构与算法:栈(九)

文章目录

(一)栈(Stack)的简介
(二)栈(Stack)的设计
(三)栈(Stack)的实现
(四)栈(Stack)的源码
(五)应用举例:浏览器的前进和后退
(六)练习:有效的括号01
(七)练习:有效的括号02
(八)练习:有效的括号03
(九)作业题

(一)栈(Stack)的简介

在这里插入图片描述

(二)栈(Stack)的设计

在这里插入图片描述
注意:对于栈,我们需要频繁的操作尾部元素,所以使用动态数组链表(双向链表)都可以,对尾部元素进行增删操作的复杂度都是O(1)

(三)栈(Stack)的实现

  • 第一种实现方法:继承,如下:

    import com.zzq.list.ArrayList;
    
    public class Stack<E> extends ArrayList<E> {
    
        public void push(E element) {
            add(element);
        }
    
        public E pop() {
            return remove(size - 1);
        }
    
        public E top() {
            return get(size - 1);
        }
    
    }
    

    效果如下:
    在这里插入图片描述
    继承会导致Stack多了很多不需要的方法,我们一般不会直接继承,会使用下面第二种方法

  • 第二种方法:组合(让ArrayList成为Stack的一部分,或者说用Stack给ArrayList做一层封装),如下:

    import com.zzq.list.ArrayList;
    import com.zzq.list.List;
    
    public class Stack<E> {
    
        private List<E> list = new ArrayList<>();
    
        public void clear() {
            list.clear();
        }
    
        public int size() {
            return list.size();
        }
    
        public boolean isEmpty() {
            return list.isEmpty();
        }
    
        public void push(E element) {
            list.add(element);
        }
    
    
        public E pop() {
            return list.remove(list.size() - 1);
        }
    
    
        public E top() {
            return list.get(list.size() - 1);
        }
    }
    

    效果也是一样的,这里不再展示了

(四)栈(Stack)的源码

其实JDK官方也提供了一个Stack类,如下:
在这里插入图片描述
它继承了Vector,是线程安全
在这里插入图片描述

(五)应用举例:浏览器的前进和后退

注意:对用户可见的是栈顶,所以浏览器正在显示的就是栈顶页面

浏览器实现前进后退功能需要用到两个栈,流程如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意:此时输入新的网址,右边的栈就要被清空(防止前进
在这里插入图片描述
其实软件的撤销(Undo)和恢复(Redo)功能也是同样的原理,如下:
在这里插入图片描述

(六)练习:有效的括号01

https://leetcode-cn.com/problems/valid-parentheses/

在这里插入图片描述
思路:我们最先拿到的{要与最后拿到的}做配对,很符合的先进后出

流程

  1. 比如字符串为{([])},遇到左字符就入栈
  2. 假设左字符全部入栈后,栈为{([(栈顶为[
  3. 此时遇到右字符]就用栈顶跟它比较,比较完就出栈

具体说明如下:
在这里插入图片描述

(七)练习:有效的括号02

代码实现如下:

    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        int len = s.length();
        for (int i = 0; i < len; i++) {
            char c = s.charAt(i);
            if (c == '(' || c == '{' || c == '[') { //左括号
                stack.push(c);
            } else { //右括号
                if (stack.isEmpty()) return false;//首先判断栈是否为空
                char left = stack.pop();//已经出栈了,只能判断是否合法,不合法就返回false
                if (left == '(' && c != ')') return false;
                if (left == '{' && c != '}') return false;
                if (left == '[' && c != ']') return false;
            }
        }
        return stack.isEmpty();
    }

(八)练习:有效的括号03

上述的代码还可以优化,如下:

    private static HashMap<Character, Character> map = new HashMap<>();

    static {
        // key(左括号) -> value(右括号)
        map.put('(', ')');
        map.put('{', '}');
        map.put('[', ']');
    }

    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        int len = s.length();
        for (int i = 0; i < len; i++) {
            char c = s.charAt(i);
            if (map.containsKey(c)) { //左括号
                stack.push(c);
            } else { //右括号
                if (stack.isEmpty()) return false;//首先判断栈是否为空
                if (c != map.get(stack.pop())) return false;
            }
        }
        return stack.isEmpty();
    }

(九)作业题

856. 括号的分数https://leetcode-cn.com/problems/score-of-parentheses/
150. 逆波兰表达式求值https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/
了解:前缀表达式、中缀表达式和后缀表达式
224. 基本计算器https://leetcode-cn.com/problems/basic-calculator/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章