棧是一種聽從後進先出(LIFO)原則的有序集合。新添加的或者待刪除的元素都保存在棧的同一端,稱做棧頂,另外一端就叫棧底。在棧裏,新元素都靠近棧頂,舊元素都接近棧底。javascript
咱們在生活中常能看到棧的例子。整齊堆起來的書,廚房堆起的盤子等java
棧也被用在編程語言的編譯器和內存中保存變量、方法調用等。git
咱們能夠選擇不一樣的數據結構來保存棧中的元素,在這裏,咱們選擇數組來保存棧中的元素。es6
/** * 使用es6中的Class語法來編寫類:棧 * 此棧使用數組來保存元素 */ class Stack { constructor() { this.items = []; } /** * 添加一個(或幾個)新元素到棧頂 * @param {*} element 新元素 */ push(element) { this.items.push(element) } /** * 移除棧頂的元素,同時返回被移除的元素 */ pop() { return this.items.pop() } /** * 返回棧頂的元素,不對棧作任何修改(這個方法不會移除棧頂的元素,僅僅返回它) */ peek() { return this.items[this.items.length - 1] } /** * 若是棧裏沒有任何元素就返回true,不然返回false */ isEmpty() { return this.items.length === 0 } /** * 移除棧裏的全部元素 */ clear() { this.items = [] } /** * 返回棧裏的元素個數。這個方法和數組的length屬性很相似 */ size() { return this.items.length } /** * 返回以字符串形式輸出的棧 */ toString() { return this.items.toString() } /** * 返回以數組形式輸出的棧 */ toArray() { return this.items } }
更多詳情請查看源碼
在計算機裏全部的內容都是二進制數字表示的(0和1),而咱們生活中主要用到十進制,還有16進制等。那麼就須要進制轉換。咱們能夠利用棧來實現轉換。github
/** * 10進制數轉換爲其餘16進制之內進制的數 * @param {*} decNumber 須要轉換的數 * @param {Int32Array} hex 進制數 */ function hexConverter(decNumber, hex) { let remStack = new Stack() let rem = 0 let baseString = '' let digits = '0123456789ABCDEF' //進製取數 if (hex < 2 || hex > 16) { return '只轉換大於二進制小於十六進制之間的進制' } while (decNumber > 0) { rem = Math.floor(decNumber % hex) // 求模運算 remStack.push(rem) decNumber = Math.floor(decNumber / hex) // 除運算 } while (!remStack.isEmpty()) { baseString += digits[remStack.pop()] // 取出棧中的數據對應於進制數的表示數 } return baseString }
更多詳情請查看源碼
正讀反讀都相同的字符序列稱爲迴文,例如「abccba」、「abcba」、「12321」、「123321」。
迴文判斷有不少種方法,在這裏,咱們能夠採用先入棧後出棧的方法,來比較入棧以前,和出棧以後兩個字符串是否相同。
空字符串究竟是不是迴文呢,有點疑惑? 我這裏定義爲不是迴文。編程
/** * 判斷字符串是否爲迴文 * @param {String} str 要判斷的字符串 */ function palindrome(str) { // 非string類型的 或者 空字符串 直接判斷不是迴文 if (typeof (str) !== 'string' || str.length === 0) { return false } let stack = new Stack() let oStr = str.toLocaleLowerCase() let nStr = '' for (let i = 0; i < str.length; i++) { stack.push(str[i]) } while (!stack.isEmpty()) { nStr += stack.pop().toLocaleLowerCase() } if (nStr === oStr) { // return `輸入的字符串【{$oStr}】是迴文` return true } else { // return `輸入的字符串【{$oStr}】不是迴文` return false } }
更多詳情請查看源碼
若是一個括號序列包含完整的左右括號對,則稱爲平衡括號序列。如:"{[()]}","", "({})", "{()}"都是平衡括號,而"{()[]", ")"則不是平衡括號。數組
括號只有三種()/[]/{}
,每種分別有左右括號。咱們能夠這樣操做:遇到左括號,左括號入棧,遇到右括號,取出棧中最後一個括號來比對的方式來判斷是否相等平衡。數據結構
/** * 判斷括號序列是否平衡,空序列也算是平衡 * @param {String} brackets 括號序列 */ function balanceBracket(brackets) { if (typeof (brackets) !== 'string') { return false } let left = '([{' let right = ')]}' let num = 0 // 括號的對數 let stack = new Stack() for (let i = 0; i < brackets.length; i++) { if (right.indexOf(brackets[0]) > -1) { return false } if (left.indexOf(brackets[i]) > -1) { stack.push(brackets[i]) num++ } else { if (right.indexOf(brackets[i]) > -1) { let topBracket = stack.pop() let rightSort = right.indexOf(brackets[i]) let leftSort = left.indexOf(topBracket) if (rightSort !== leftSort) { return false } } } } if (!stack.isEmpty()) return false // 2019-5-30 更新,考慮狀況 [[[() return `是平衡括號序列。有${num}對括號` }
更多詳情請查看源碼
有三根相鄰的柱子,標號爲A,B,C。A柱子上從下到上按金字塔狀疊放着n個不一樣大小的圓盤,要把全部圓盤移動到B柱子上。
要求:編程語言
問題:
請問至少須要移動多少次圓盤?每次移動的步驟是怎樣的?this
let num = 0 // 記錄移動的次數 /** * 記錄圓盤移動的過程 * * 這裏的思路,一直在循環作一件事情。 * 把原始柱子上的圓盤分爲兩部分,最大和其它。 * 第一回合,將其它移動到輔助柱子上,將最大的移動到目標柱子上,再將其它移動到目標柱子上 * 第二回合,將其它移動到輔助柱子上,將最大的移動到目標柱子上,再將其它移動到目標柱子上 * ... * 第2 ** n - 1回合,將其它移動到輔助柱子上,將最大的移動到目標柱子上,再將其它移動到目標柱子上 * * 可是,這裏源柱子、輔助柱子和目標柱子會隨着其它盤而變更。 * 其它盤在哪一個柱子上,哪根柱子就是源柱子。 * @param {Int32Array} plates 圓盤個數 * @param {Array} source 源柱子 * @param {Array} helper 輔助柱子 * @param {Array} dest 目的地柱子 * @param {String} sourceName 源柱子的名字 * @param {String} helperName 輔助柱子的名字 * @param {String} destName 目的地柱子的名字 * @param {Array} moves 步驟存儲器,存儲每一步的流程 */ function moveOfHanoi( plates, source, helper, dest, sourceName, helperName, destName, moves = [] ) { if (plates <= 0) { return moves } else if (plates === 1) { // 彈出源柱子上剩下的最大圓盤,並將其壓入目標柱子 dest.push(source.pop()) num++ let sourceArr = source.toString() let helperArr = helper.toString() let destArr = dest.toString() let movestr = `第 ${num} 步,將圓盤 ${plates} 從 ${sourceName} 移至 ${destName}; ${sourceName}: [${sourceArr}],${helperName}: [${helperArr}],${destName}: [${destArr}]` moves.push(movestr) } else { moveOfHanoi( plates - 1, source, dest, helper, sourceName, destName, helperName, moves ) // 彈出源柱子上剩下的最大圓盤,並將其壓入目標柱子 dest.push(source.pop()) num++ let sourceArr = source.toString() let helperArr = helper.toString() let destArr = dest.toString() let movestr = `第 ${num} 步,將圓盤 ${plates} 從 ${sourceName} 移至 ${destName}; ${sourceName}: [${sourceArr}],${helperName}: [${helperArr}],${destName}: [${destArr}]` moves.push(movestr) moveOfHanoi( plates - 1, helper, source, dest, helperName, sourceName, destName, moves ) } return moves } /** * 漢諾塔 * 記錄每一次圓盤移動的動做。從${源柱子}到${目標柱子} * @param {Int32Array} plates 圓盤的個數 * @param {String} sourceName 源柱子的名稱 * @param {String} helperName 輔助柱子的名稱 * @param {String} destName 目標柱子的名稱 */ function hanoiStackArray(plates, sourceName, helperName, destName) { let source = new Stack() let helper = new Stack() let dest = new Stack() for (let i = plates; i > 0; i--) { source.push(i) } num = 0 return moveOfHanoi( plates, source, helper, dest, sourceName, helperName, destName ) }
[完]