資料結構-棧

小橘子ღ發表於2020-07-05

棧的基本特點

  • 先進後出, 後進先出(LIFO, Last in First Out)
  • 除頭尾節點外, 每個節點都有前驅和後繼節點

棧的基本操作

  • 壓棧(push), 將資料放入棧頂。
  • 彈棧(pop), 將資料從棧頂移除。

通過下圖來認識一下棧:

avatar

棧的一些應用

舉兩個例子

  1. 編輯器都有一個undo(即撤銷)操作, 比如我們在IDEA中寫程式碼寫錯了, 想要撤銷到修改之前該怎麼辦呢? 就需要執行undo操作了。
    對於編輯器來說undo操作的原理是什麼呢?
    其實就是依靠棧(Stack)來維護的, 如下過程:
* 輸入**沉迷**, 編輯器就會記錄這個動作。這個記錄方式其實就是把這個動作放入棧中, 記錄了**沉迷**
* 然後輸入**學習**, 編輯器的棧會在記錄一次, 以同樣的方式壓入棧中。
* 下面如果我要輸入**無法**但卻輸入了**無天**, 棧中也記錄了這個動作。發現輸入出錯後, 需要撤銷這個操作, 這裡需要怎麼做?
  * 其實是從編輯器的這個棧中取出棧頂元素, 而棧頂記錄的操作是輸入出錯的"無天", 執行撤銷就是刪除這兩個字。也就是把這兩個字從棧頂中移除。
複製程式碼
  1. 在比如說我們系統程式的呼叫, 比如有A,B,C三個方法, A呼叫了B, B呼叫了C, 那麼當A方法中執行到呼叫B方法的時候會將A方法壓入系統棧, 當B呼叫C的時候會把B方法壓入棧, 當C方法執行完畢後, 會從棧中找出上一次執行中斷的方法再次執行, 直到棧中為空。如下圖:

avatar

avatar

棧的實現

  • 入棧
  • 出棧
  • 棧頂元素
  • 棧的長度
  • 棧是否為空

我們從上面幾個點來看看怎麼設計一個Stack。
這裡需要注意下, 我們可能會用佇列, 陣列或者是連結串列等結構來建立一個棧, 但是棧的功能都是一樣的, 只不過是底層資料結構不同, 所以這裡抽出一個介面來實現不同的型別的棧。

public interface Stack<E> {
    // 獲取棧的長度
    int getSize();
    // 判斷棧是否為空
    boolean isEmpty();
    // 資料壓棧(add)
    void push(E e);
    // 資料彈棧(remove)
    E pop();
    // 獲取棧頂元素
    E peek();
}
複製程式碼
/**
 * Created by Joker on 19/9/14.
 * 利用陣列來實現棧的功能
 */
public class ArrayStack<E> implements Stack<E> {

    Array<E> array ;


    public ArrayStack(int capacity) {
        this.array = new Array<>(capacity);
    }

    public ArrayStack() {
        this.array = new Array<>();
    }

    @Override
    public int getSize() {
        return array.getSize();
    }

    @Override
    public boolean isEmpty() {
        return array.isEmpty();
    }

    @Override
    public void push(E e) {
        array.addLast(e);
    }

    @Override
    public E pop() {
        return array.removeLast();
    }

    @Override
    public E peek() {
        return array.getLast();
    }

    @Override
    public String toString() {
        StringBuffer buff = new StringBuffer();
        buff.append("Stack: [");
        for (int i = 0; i < array.getSize(); i ++) {
            buff.append(array.get(i));
            if (i < array.getSize() - 1)
                buff.append(",");
        }

        buff.append("] top");
        return buff.toString();
    }
}

複製程式碼

現在已經對棧有了基本的瞭解, 我們來看一道題目。
給定一個只包括 '(',')','{','}','[',']' 的字串,判斷字串是否有效。 有效字串需滿足:

  1. 左括號必須用相同型別的右括號閉合。
  2. 左括號必須以正確的順序閉合。

例子:
輸入: "()" 輸出: true

輸入: "()[]{}" 輸出: true

輸入: "([)]" 輸出: false

輸入: "{[]}" 輸出: true

輸入: "(]" 輸出: false

下面的示例程式碼比較笨重, 使用棧來解決

public boolean isValid(String s) {
        java.util.Stack<Character> stack = new Stack<>();

        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c == '[' || c == '{' || c == '(') {
                stack.push(c);
            } else {

                if (stack.isEmpty())
                    return false;

                Character character = stack.pop();
                if (c == ')' && character != '(')
                    return false;
                if (c == '}' && character != '{')
                    return false;
                if (c == ']' && character != '[')
                    return false;
            }
        }

        return stack.isEmpty()
}
複製程式碼

avatar

相關文章