戀上數據結構與算法:棧(九)

文章目錄

(一)棧(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/

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