栈是一种听从后进先出(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 ) }
[完]