棧引發的問題思考
- 2019 年 10 月 31 日
- 筆記
ECMAScript數組也提供了一種讓數組的行為類似於其他數據結構的方法。具體說來,數組可以表現得就像棧一樣,後者是一種可以限制插入和刪除項的數據結構。
棧是一種LIFO(Last-In-First-Out,後進先出)的數據結構,也就是最新添加的項最早被移除。而棧中項的插入(叫做推入)和移除(叫做彈出),只發生在一個位置——棧的頂部。ECMAScript為數組專門提供了 push() 和 pop() 方法,以便實現類似棧的行為。
push() 方法可以接收任意數量的參數,把它們逐個添加到數組末尾,並返回修改後數組的長度。而 pop() 方法則從數組末尾移除最後一項,減少數組的 length 值,然後返回移除的項。
棧的應用
01
可以利用棧將一個數字從一種數制轉換成另一種數制。假設想將數字 n 轉換為以 b 為基數的數字,實現轉換的演算法如下。
(1) 最高位為 n % b,將此位推入棧。
(2) 使用 n/b 代替 n。
(3) 重複步驟 1 和 2,直到 n 等於 0,且沒有餘數。
(4) 持續將棧內元素彈出,直到棧為空,依次將這些元素排列,就得到轉換後數字的字元串形式。
使用棧,在 JavaScript 中實現該演算法就是小菜一碟。下面就是該函數的定義,可以將數字轉化為二至九進位的數字:
function mulBase(num, base) { let list = [] do { list.push(num % base) num = Math.floor(num /= base) } while (num > 0) let converted = '' while (list.length > 0) { converted += list.pop() } return converted } let num = 100 console.log(mulBase(num, 2)) // 1100100 console.log(num.toString(2)) // 1100100
02
迴文是指這樣一種現象:一個單詞、短語或數字,從前往後寫和從後往前寫都是一樣的。比如,單詞「dad」、「racecar」就是迴文;如果忽略空格和標點符號,下面這個句子也是迴文,「A man, a plan, a canal: Panama」;數字 1001 也是迴文。
使用棧,可以輕鬆判斷一個字元串是否是迴文。我們將拿到的字元串的每個字元按從左至右的順序推入棧。當字元串中的字元都入棧後,棧內就保存了一個反轉後的字元串,最後的字元在棧頂,第一個字元在棧底。
字元串完整壓入棧內後,通過持續彈出棧中的每個字母就可以得到一個新字元串,該字元串剛好與原來的字元串順序相反。我們只需要比較這兩個字元串即可,如果它們相等,就是一個迴文。
function isPalindrome(word) { let list = [] for(let i = 0; i < word.length; i++) { list.push(word[i]) } let rword = '' while (list.length > 0) { rword += list.pop() } return word === rword }
03
為了演示如何用棧實現遞歸,考慮一下求階乘函數的遞歸定義。首先看看 5 的階乘是怎麼定義的。
使用棧來模擬計算 5! 的過程,首先將數字從 5 到 1 推入棧,然後使用一個循環,將數字挨個彈出連乘,就得到了正確的答案:120。
function fact(n) { let list = [] while (n > 1) { list.push(n--); } let product = 1 while (list.length > 0) { product *= list.pop() } return product } console.log(fact(5)) // 150
數據結構是電腦存儲、組織數據的方式。數據結構是指相互之間存在一種或多種特定關係的數據元素的集合。通常情況下,精心選擇的數據結構可以帶來更高的運行或者存儲效率。
——《基本概念》
提問
棧可以用來判斷一個算術表達式中的括弧是否匹配。編寫一個函數,該函數接受一個算術表達式作為參數,返回括弧缺失的位置。下面是一個括弧不匹配的算術表達式的例子:
2.3 + 23 / 12 + (3.14159×0.24