棧:棧的“後進先出”是什麼意思?原理圖解

想象一下,你每天早上用的盤子,剛洗完的盤子會疊放在一起。最上面的盤子是你剛放上去的,要拿盤子的時候,你必須先把最上面的那個拿走,對吧?這個“先放的在下面,後放的在上面,拿的時候先拿上面的”的過程,其實就是我們今天要講的數據結構——棧的核心特性。

一、棧是什麼?

棧(Stack)是一種特殊的線性表,它的特殊之處在於:只能從一端進行插入和刪除操作。我們把這個操作的一端叫做“棧頂”,另一端叫做“棧底”。就像疊盤子,棧底是最下面的盤子,棧頂是最上面的盤子;只能在棧頂放盤子(入棧)或拿盤子(出棧),不能從棧底操作。

二、核心特性:後進先出(LIFO)

棧最關鍵的特性是“後進先出”(Last In First Out,簡稱LIFO)。意思是:最後放入棧的元素,會最先被取出

舉個生活例子:
- 你把彈夾裏的子彈一顆顆壓進去,最後壓進去的子彈在最上面。開槍時,你會先射出最上面的那顆子彈(最後壓進去的),這就是“後進先出”。
- 疊被子:週一疊的被子在最下面,週二疊的在上面,你整理時會先疊週二的被子(後疊的),這也是LIFO。

對比一下隊列(先進先出,FIFO):排隊買票時,先到的人先買到票(先入先出);而棧就像“插隊”,最後插隊的人反而先被處理。

三、棧的基本操作

棧只有兩個核心操作:入棧(push)出棧(pop),還可以查看棧頂元素(top)或判斷棧是否爲空(empty)。

  • 入棧(push):往棧頂添加一個元素。
    比如:你往盤子堆裏放一個新盤子,這個盤子會成爲新的棧頂。
  • 出棧(pop):從棧頂移除一個元素,並返回該元素。
    比如:你從盤子堆裏拿走最上面的盤子,這個盤子就是棧頂元素,拿走後棧頂變成下一個盤子。
  • 查看棧頂(top):不刪除元素,只看棧頂的元素(比如你想看看最上面的盤子是什麼樣的)。
  • 判空(empty):檢查棧裏是否還有元素(比如你想知道盤子堆是否空了)。

四、棧的原理圖解(用例子理解)

假設我們按順序執行以下操作,用數字標記入棧順序,用箭頭表示出棧順序:

  1. 初始狀態:棧爲空(用 [] 表示,[] 中左邊是棧底,右邊是棧頂)。
    棧:[]

  2. 入棧1(push 1):往棧頂加1,此時棧頂是1。
    棧:[1]

  3. 入棧2(push 2):往棧頂加2,此時棧頂是2(1在棧底,2在棧頂)。
    棧:[1, 2]

  4. 入棧3(push 3):往棧頂加3,此時棧頂是3(順序:1→2→3,棧底到棧頂)。
    棧:[1, 2, 3]

  5. 出棧(pop):從棧頂拿走3,此時棧頂變成2。
    棧:[1, 2]
    (彈出元素:3)

  6. 出棧(pop):從棧頂拿走2,此時棧頂變成1。
    棧:[1]
    (彈出元素:2)

  7. 出棧(pop):從棧頂拿走1,此時棧爲空。
    棧:[]
    (彈出元素:1)

五、棧的實際應用場景

棧在編程和生活中無處不在,以下是幾個經典例子:

  1. 括號匹配:比如判斷表達式 (a + b) * (c - d) 是否合法。用棧記錄左括號,遇到右括號就彈出棧頂的左括號,最後棧空則合法(否則括號不匹配)。
  2. 函數調用棧:當你寫一個程序時,調用 main 函數,main 裏調用 func1func1 裏調用 func2func2 執行完後會先返回 func1func1 執行完返回 main。這就是棧的“後進先出”特性(後調用的函數先返回)。
  3. 瀏覽器後退功能:你打開網頁1→網頁2→網頁3,後退時會依次回到網頁2→網頁1,相當於彈出棧頂元素(網頁3→網頁2→網頁1)。
  4. 表達式求值:比如計算 3 + 4 * 2 / (1 - 5),需要用棧處理運算符優先級,先算括號、再乘除、最後加減。

六、總結

棧是一種“後進先出”的線性結構,只能從棧頂操作元素。它的核心是“LIFO”,在括號匹配、函數調用、瀏覽器後退等場景中發揮關鍵作用。記住:棧就像疊盤子,後放的先拿,先放的後拿

理解棧的基本操作和特性後,你會發現它是解決很多問題的“利器”,比如後續學習遞歸、動態規劃時,棧也會經常被用到。

(PS:如果覺得抽象,可以拿個筆筒模擬:把筆從下往上依次插入,每次拿最上面的筆,就是棧的“後進先出”啦!)

小夜