Java學習72:使用Stack

還是先創建包com.tenth.stack,在包下創建Demo12.java
在這裏插入圖片描述
我們在前面瞭解到了單向進出、優先進出和雙向進出,我們這次瞭解一個叫棧(Stack)的隊列。
還記得Queue嗎?它是一種單向進出的隊列,同樣,棧也是單向進出,但是他們又有不同之處:

  • Queue一定是先進的先出
  • Stack一定是先進的後出

理解這兩個原理,就很簡單。

在Stack中,只有入棧和出棧的操作:

  • 把元素壓棧:push(E);
  • 把棧頂的元素“彈出”:pop(E);
  • 取棧頂元素但不彈出:peek(E);

爲了更容易理解,這兒我多說兩句:相信大家小時候一定玩過手槍吧。我們可以把手槍的彈夾理解成一個棧,仔細想想,是不是先裝進去的子彈最後打出來,反而後裝進去的子彈先打出來;

在Java中,由於沒有單獨的Stack接口,所以我們一般都是使用Deque接口來模擬一個Stack,一共有以下三個功能:

  • 把元素壓棧:push(E)/addFirst(E);
  • 把棧頂的元素彈出來:pop(E)/removeFirst();
  • 取棧頂的元素但是不彈出來:peek()/peekFirst();

當我們把Deque作爲Stack使用時,注意只調用push()/pop()/peek()方法,不要調用addFirst()/removeFirst()/peekFirst()方法,這樣代碼更加清晰。

Stack的作用
其實在很多的項目中,都有棧這個概念。同樣,棧也是我們用的最多的一個接口,例如:

static void main(String[] args) {
    foo(123);
}

static String foo(x) {
    return "F-" + bar(x + 1);
}

static int bar(int x) {
    return x << 2;
}

JVM會創建方法調用棧,每調用一個方法時,先將參數壓棧,然後執行對應的方法;當方法返回時,返回值壓棧,調用方法通過出棧操作獲得方法返回值。

因爲方法調用棧有容量限制,嵌套調用過多會造成棧溢出,即引發StackOverflowError:

public class Demo12 {
    public static void main(String[] args) {
        try {
            increase(1);
        }catch (StackOverflowError e){
            System.out.println("錯誤信息:"+e);
        }
    }
    static int increase(int x){
        return increase(x)+1;
    }
}

在這裏插入圖片描述
這種就會引發一個棧溢出的錯誤;

我們再來看一個Stack的用途:對整數進行進制的轉換就可以利用棧。

例如,我們要把一個int整數12500轉換爲十六進制表示的字符串,如何實現這個功能?

首先我們準備一個空棧:
在這裏插入圖片描述
然後計算12500÷16=781…4,餘數是4,把餘數4壓棧:
在這裏插入圖片描述
然後計算781÷16=48…13,餘數是13,13的十六進制用字母D表示,把餘數D壓棧:
在這裏插入圖片描述
然後計算48÷16=3…0,餘數是0,把餘數0壓棧:
在這裏插入圖片描述
最後計算3÷16=0…3,餘數是3,把餘數3壓棧:
在這裏插入圖片描述
當商是0的時候,計算結束,我們把棧的所有元素依次彈出,組成字符串30D4,這就是十進制整數12500的十六進制表示的字符串。

計算中綴表達式
在編寫程序的時候,我們使用的帶括號的數學表達式實際上是中綴表達式,即運算符在中間,例如:1 + 2 * (9 - 5)。

但是計算機執行表達式的時候,它並不能直接計算中綴表達式,而是通過編譯器把中綴表達式轉換爲後綴表達式,例如:1 2 9 5 - * +。

這個編譯過程就會用到棧。我們先跳過編譯這一步(涉及運算優先級,代碼比較複雜),看看如何通過棧計算後綴表達式。

計算後綴表達式不考慮優先級,直接從左到右依次計算,因此計算起來簡單。首先準備一個空的棧:
在這裏插入圖片描述
然後我們依次掃描後綴表達式1 2 9 5 - * +,遇到數字1,就直接扔到棧裏:
在這裏插入圖片描述
緊接着,遇到數字2,9,5,也扔到棧裏:
在這裏插入圖片描述
接下來遇到減號時,彈出棧頂的兩個元素,並計算9-5=4,把結果4壓棧:
在這裏插入圖片描述
接下來遇到號時,彈出棧頂的兩個元素,並計算24=8,把結果8壓棧:
在這裏插入圖片描述
接下來遇到+號時,彈出棧頂的兩個元素,並計算1+8=9,把結果9壓棧:
在這裏插入圖片描述
掃描結束後,沒有更多的計算了,彈出棧的唯一一個元素,得到計算結果9。

小結
棧(Stack)是一種後進先出(LIFO)的數據結構,操作棧的元素的方法有:

  • 把元素壓棧:push(E);
  • 把棧頂的元素“彈出”:pop(E);
  • 取棧頂元素但不彈出:peek(E)。

在Java中,我們用Deque可以實現Stack的功能,注意只調用push()/pop()/peek()方法,避免調用Deque的其他方法。

最後,不要使用遺留類Stack。

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