栈是一个后进先出的数据结构
JavaScript中没有栈,但可以用Array实现栈的所有功能
栈常见操作:push、pop、stack[stack. length-1]
1. 定义 后进先出,相当于往容器里放东西
用途:
编程语言的编译器和内存中保存变量、方法调用
浏览器历史记录(浏览器的返回按钮)
函数堆栈调用
……
2. 具体操作 创建
1 2 3 4 5 class Stack { constructor ( ) { this .items = []; } }
方法 :
push(element(s)):添加一个(或几个)新元素到栈顶
1 2 3 push (element ) { this .items.push(element); }
pop():移除栈顶的元素,同时返回被移除的元素
1 2 3 pop ( ) { return this .items.pop(); }
peek():返回栈顶的元素,不对栈做任何修改(该方法不会移除栈顶的元素,仅仅返回它)
1 2 3 peek ( ) { return this .items[this .items.length - 1 ]; }
isEmpty():如果栈里没有任何元素就返回true,否则返回false
1 2 3 isEmpty ( ) { return this .items.length === 0 ; }
clear():移除栈里的所有 元素
1 2 3 clear ( ) { this .items = []; }
size():返回栈里的元素个数(和length 属性类似)
1 2 3 size ( ) { return this .items.length; }
3. 使用 1 2 3 4 5 6 7 8 9 10 11 const stack = new Stack(); console .log(stack.isEmpty()); stack.push(5 ); console .log(stack.peek()); console .log(stack.size()); console .log(stack.isEmpty()); stack.push(8 ); stack.push(11 ); stack.pop(); stack.pop(); console .log(stack.size());
4. 基于JavaScript对象的Stack类
最简单的方式:使用数组来存储其元素
基本结构:
1 2 3 4 5 6 7 class xxx { constructor ( ) { } }
5. 保护数据结构内部元素 使用 “_” “#” 前缀来声明私有属性,需要编写相应的代码逻辑
使用es6中的Symbol
使用es6中的WeakMap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const items = new WeakMap ();class Stack { construtor ( ) { items.set(this , []); } push (element ) { const s = items.get(this ); s.push(element); } pop ( ) { const s = items.get(this ); const r = s.pop(); return r; } }
6. 应用 十进制 —> 二进制 通过二进制的计算方法,可以知道二进制的结果是余数从高位到低位排列的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 decimalToBinary = (decNumber ) => { const remStack = new Stack(); let number = decNumber; let rem; let binaryString = '' ; while (number > 0 ) { rem = Math .floor(number % 2 ); remStack.push(rem); number = Math .floor(number / 2 ); } while (!remStack.isEmpty()) { binaryString += remStack.pop().toString(); } return binaryString; }
其他进制转换 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 function baseConverter (decNumber, base ) { const remStack = new Stack(); const digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' ; let number = decNumber; let rem; let baseString = '' ; if (!(base >= 2 && base <= 36 )) { return '' ; } while (number > 0 ) { rem = Math .floor(number % base); remStack.push(rem); number = Math .floor(number / base); } while (!remStack.isEmpty()) { baseString += digits[remStack.pop()]; } return baseString; }console .log(baseConverter(1111111 , 3 ));
函数的堆栈调用 1 2 3 4 5 6 7 const func1 = () => { func2(); }const func2 = () => { func3(); }const func3 = () => {}
我们使用node进行debug:
可以看到,实际上,函数的调用也是满足后进先出的顺序
即,func3()最后进去,最先执行完的是func3()
一道LeetCode题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 var isValid = function (s ) { const stack = []; for (let i = 0 ; i < s.length; i++) { const c = s[i]; if (c === '(' || c=== '{' || c === '[' ) { stack.push(c); } else { const t = stack[stack.length - 1 ]; if ( (t === '(' && c === ')' ) || (t === '{' && c === '}' ) || (t === '[' && c === ']' ) ) { stack.pop(); } else { return false ; } } } return stack.length === 0 ; };