描述

栈是属于一种后进先出的结构(LIFO), 而定义栈的规则就是只能从顶部添加或者压入, 从顶部获取, 不能直接操作栈底的元素, 如下图, 依次添加 9 6 3 1
堆栈 - 图1结构概念: 入栈, 出栈, 栈顶(最后一个添加入栈), 栈底(最先添加入栈), 映射到理解的数组中时, 栈顶就是数组的末尾, 栈底就是第一个
操作:

  • push(入栈): 向栈中添加一个元素
  • pop(出栈): 移除栈顶的元素, 并返回该元素
  • peek(检查栈顶元素): 仅仅只是返回栈顶的元素, 并不会删除
  • isEmpty(是否为空): 检查栈是否为空
  • clear(清空): 清空栈
  • size(长度): 查看栈的长度

    实现

    ```javascript // es5 function Stack() { const items = [];

    this.push = function(ele) { items.push(ele); };

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

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

    this.size = function() { return items.length; };

    this.isEmpty = function() { return this.size() === 0; };

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

// es6 class Stack { constructor() { this.items = []; }

push(ele) { this.items.push(ele); }

pop() { return this.items.pop(); }

peek() { return this.items[this.size() - 1]; }

isEmpty() { return this.size() === 0; }

size() { return this.items.length; }

clear() { this.items = []; } }

  1. <a name="ecff77a8"></a>
  2. ### 使用
  3. <a name="121068bd"></a>
  4. #### [十进制](https://zh.wikipedia.org/wiki/%E5%8D%81%E8%BF%9B%E5%88%B6)转[二进制](https://zh.wikipedia.org/wiki/%E4%BA%8C%E8%BF%9B%E5%88%B6)
  5. 十进制: 以10 为基础进位的数字, 由0,1,2,3,4,5,6,7,8,9 十个数字组成<br />二进制: 以2 为基础进位, 主要是计算机使用, 由 0 和 1 组成
  6. ```javascript
  7. function divideBy2(number) {
  8. let $$num = number; // 备份, 不修改原参数
  9. const remStack = new Stack();
  10. let binaryString = '';
  11. let rem; // 余数
  12. while(num > 0) {
  13. rem = $$num % 2;
  14. remStack.push(rem);
  15. $$num = Math.floor($$num / 2);
  16. }
  17. // 此处为什么不能使用数组的 reduce 以及区别
  18. while(!remStack.isEmpty()) {
  19. binaryString += remStack.pop(); // 出栈拼接
  20. }
  21. /**
  22. 使用数组进行拼接, 时间貌似是短了点
  23. binaryString = remStack.getItems().reverse().reduce((prev, next) => {
  24. prev += next;
  25. return prev;
  26. }, '');
  27. */
  28. return binaryString;
  29. }
  30. // 测试
  31. console.log(divideBy2(10)); // 1010
  32. console.log(divideBy2(8)); // 1000

当然不使用栈结构处理也是可以实现的, 但是我们需要学习的是一种结构或者是思想

// 非栈结构实现, 在拼接时也可以使用数组本身的pop 方法获取类似栈顶的数字
function divideBy2(decNumber) {
  const arr = [];
  let $$num = decNumber;
  let rem;

  while ($$num > 0) {
    rem = $$num % 2;
    arr.push(rem);
    $$num = Math.floor($$num / 2);
  }

  return arr.reverse().reduce((prev, next) => {
    return prev.concat(next);
  }, '');
}

疑问

  • 为什么在 ES5中的实现中, 使用的是 定义内部变量而不是使用 this.items = []; 呢 ?

解: 根据函数内是一个单独的作用域, 外部访问不到, 所以从外部是无法修改内部定义的变量. 而使用了 this.items = [] 之后 在实例的属性上就会带有 items, 此时假设使用 stack.items = []就能将内部的状态修改掉, 等于破坏了原本设定的结构

  • 在转换时为什么需要 Math.floor ?

解: 以 2 为被除数时, 出现有浮点数, 后续无法再次操作, 二进制为 0, 1

  • 为什么是余数入栈 ? 为什么是栈底的数字放在二进制的最后 ?

其他

函数调用栈

视频

2.2 栈概念,基于js的栈类方法实现 —— 数据结构与算法 javascript描述(栈、队列、链表、集合、字典、树、图 系列课程详解 ).mp4 (84.46MB)