在 JavaScript 中,陣列就是一個最簡單的棧了,在尾部操作的pop
、push
也對應著出入棧的操作。so ?
棧只是種抽象概念,用連結串列 or 其它方式實現它均可。應用之解決問題正是它存在的原因
場景一:遞迴
從前山上有座廟,廟裡有個老和尚和小和尚,老和尚給小和尚講故事:“從前山上有座廟......”
有名的斐波那契數列,手動地計算相當困難,即便有計算器在手。而在程式語言中,使用遞迴可以很好地解決這個難題:
function F(n) {
return F(n-1) + F(n-2);
}
複製程式碼
重點來了,計算機如何實現遞迴?這是一個很籠統的概念,因為等於這個加那個,那個再加這個...... 知其所以然而不知其然。應用棧的結構,我們可以把未知的結果推入棧內,在彈出的時候逐個計算。 如下圖
程式碼解釋:
function recursion() {
// 呼叫棧
const stack = [];
// 解析時
// 推入棧
// 一般來說,棧有大小限制,如果自己寫了個無限遞迴的函式,那呼叫棧一直增加,最後溢位
for (let i = n; i > 0; i--) {
stack.push(F(i));
}
// 執行時
// 後入先出,彈出
for (let i = 3; i <= n; i++) {
F(n-2) = stack.pop();
F(n-1) = stack.pop();
F(n) = F(n-1) + F(n-2)
// 計算完成後再推入棧內
stack.push(F(n))
}
// 執行完成,棧內剩下最終結果,彈出並返回
if (n) return stack.pop()
}
複製程式碼
場景二:四則運算
數學老師:“先乘除,後加減,有括號先算括號。”
分析下計算機四則運算的步驟:
- 定義運算子功能
- 優先順序:乘除 >> 加減
- 有括號優先計算括號
示例:(1 + 2) x 3 - 4 ÷ 5
括號內優先計算,立馬得出結果,咋一想還蠻符合佇列的規則,先入先出嘛。但在有多個括號的情況下,優先計算最裡面的括號,這樣就只能推入棧中慢慢計算了。
但是怎麼優雅地推入棧內計算,有個偉大的科學家解決了這個難題,波蘭邏輯學家想到了一種不需要括號的字尾表示式,稱之為逆波蘭。
示例字尾表示式:12+3*45/-
字尾表示式計算過程:
轉化後的計算簡直不要太簡單,來看看又是如何利用棧來轉的:
最後
直接從《大話資料結構》搬過來的磚。。。不過這本書真的比清華版資料結構易懂多了,正在啃的同學安利下