栈数据结构

栈是一种后进先出的有序集合,有栈顶和栈底。

创建栈

  1. //创建一个类来表示栈
  2. function Stack() {}

首先,我们可以用数组来保存栈里的元素:

  1. let items = []

接下来要为栈声明一些方法:

push()、pop()、peek()、isEmpty()、clear()、size()。

向栈添加元素

  1. this.push = function(element) {
  2. items.push(element)
  3. };

从栈移除元素

  1. this.pop = function() {
  2. return items.pop();
  3. };

查看栈顶元素

  1. this.peek = function() {
  2. return items[items.length - 1];
  3. };

检查栈是否为空

  1. this.isEmpty = function() {
  2. return items.length == 0;
  3. };
  4. this.size = function () {
  5. return item.length;
  6. }

清空和打印栈元素

  1. this.clear = function() {
  2. items = [];
  3. };

栈已经完成,在添加一个print方法,输出栈里的元素:

  1. this.print = function() {
  2. console.log(item.toString());
  3. }

使用Stack类:

  1. let stack = new Stack();
  2. stack.push(5);
  3. stack.push(8);
  4. ......

ES6和stack类

  1. class Stack{
  2. constructor() {
  3. this.items = [];
  4. }
  5. push(element) {
  6. this.items.push(element);
  7. }
  8. ...
  9. }

items变量是公共的,我们希望用户只能访问暴露给类的方法,否则就有可能从栈的中间移除元素(因为我们用数组来存储其值),这不是我们希望看到的。

  1. let a = new Stack();
  2. a.items = [1,2,3,4,5]
  3. a.items.splice(1,2)
  4. console.log(a); //Stack { items: [ 1, 4, 5 ] }

所以我们要创建私有属性:

  1. // 1.用ES6的限定作用域Symbol实现类
  2. let _items = Symbol();
  3. class Stack {
  4. constructor() {
  5. this[_items] = []
  6. }
  7. }

这个方法创建了一个假的私有属性,因为ES6的Object.getOwnPropertySymbols方法能够取到类里面声明的所有Symbol属性。下面是一个破坏Stack类的例子:

  1. let stack = new Stack();
  2. stack.push(5);
  3. stack.push(8);
  4. let objectSymbols = Object.getOwnPropertySymbols(stack);
  5. console.log(objectSymbols.length); //1
  6. console.log(objectSymbols); //[Symbol()]
  7. console.log(objectSymbols[0].push(1));
  8. stack.print(); //5,8,1
  1. // 2.用ES6的WeakMap实现类
  2. // 有一种数据类型可以确保属性是私有的,这就是WeakMap,可以存储键值对,键是对象,值可以是任意数据类型
  3. const items = new WeakMap();
  4. class Stack{
  5. constructor() {
  6. items.set(this,[]);
  7. }
  8. push(element) {
  9. let s = items.get(this);
  10. s.push(element);
  11. }
  12. pop() {
  13. let s = items.get(this);
  14. let r = s.pop();
  15. return r;
  16. }
  17. ...
  18. }

现在items是真正的私有属性了,但还有一件事要做。items现在仍然是在Stack类以外声明的,因此谁都可以改动他。我们要用一个闭包把Stack类包起来,这样就只能在这个函数里访问WeakMap:

  1. let Stack = (function() {
  2. const items = new WeakMap();
  3. class Stack{
  4. constructor() {
  5. items.set(this,[]);
  6. }
  7. ...}
  8. return Stack;
  9. })();

然而用这种方法的话,扩展类无法继承私有属性。

用栈解决问题

从十进制到二进制

  1. function dec2bin(decNumber) {
  2. let stack = new Stack()
  3. while (decNumber > 0 ) {
  4. stack.push(decNumber % 2)
  5. decNumber = Math.floor(decNumber / 2)
  6. }
  7. let binaryString = ''
  8. while(!stack.isEmpty()) {
  9. binaryString += stack.pop()
  10. }
  11. return binaryString
  12. }
  13. console.log(dec2bin(100)); //1100100