定场诗

  1. 金山竹影几千秋,云索高飞水自流;
  2. 万里长江飘玉带,一轮银月滚金球。
  3. 远自湖北三千里,近到江南十六州;
  4. 美景一时观不透,天缘有分画中游。

前言

本章是重读《学习JavaScript数据结构与算法-第三版》的系列文章,本章为各位小伙伴分享数据结构-的故事,请让胡哥带你走进的世界

何为栈?栈是一种遵从后进先出(LIFO)原则的有序集合。

新添加或待删除的元素都保存在栈的同一端,称作栈顶;另一端就叫栈底。

在栈里,新元素都靠近栈顶,旧元素都接近栈底。

基于数组的栈

我们将创建一个基于数组的栈,了解栈的结构、运行规则

  1. /**
  2. * 基于数组array的栈Stack
  3. * @author huxiaoshuai
  4. */
  5. class Stack {
  6. // 初始化
  7. constructor () {
  8. this.items = []
  9. }
  10. }

使用数组保存栈里的元素

数组允许我们在任何位置添加和删除元素,那基于栈遵循LIFO原则,我们对元素的插入和删除功能进行封装

方法 描述
push(element(s)) 添加一个(或多个)新元素到栈顶
pop() 移除栈顶元素,同时返回被移除的元素
peek() 返回栈顶的元素,不对栈做任何修改
isEmpty() 判断栈是否为空,为空则返回true,否则返回false
clear() 移除栈的所有元素
size() 返回栈的元素个数

代码实现

  1. class Stack {
  2. // 初始化
  3. constructor () {
  4. this.items = []
  5. }
  6. /**
  7. * push() 添加元素到栈顶
  8. */
  9. push (element) {
  10. this.items.push(element)
  11. }
  12. /**
  13. * pop() 移除栈顶元素并返回
  14. */
  15. pop () {
  16. return this.items.pop()
  17. }
  18. /**
  19. * peek() 返回栈顶部元素
  20. */
  21. peek () {
  22. return this.items[this.items.length - 1]
  23. }
  24. /***
  25. * isEmpty() 检测栈是否为空
  26. */
  27. isEmpty () {
  28. return this.items.length === 0
  29. }
  30. /**
  31. * size() 返回栈的长度
  32. */
  33. size () {
  34. return this.items.length
  35. }
  36. /**
  37. * clear() 清空栈元素
  38. */
  39. clear () {
  40. this.items = []
  41. }
  42. }

使用Stack类

  1. const stack = new Stack()
  2. console.log(stack.isEmpty()) // true
  3. // 添加元素
  4. stack.push(5)
  5. stack.push(8)
  6. // 输出元素
  7. console.log(stack.peek()) // 8
  8. stack.push(11)
  9. console.log(stack.size()) // 3
  10. console.log(stack.isEmpty()) // false
  11. stack.push(15)

基于以上栈操作的示意图

  1. stack.pop()
  2. stack.pop()
  3. console.log(stack.size()) // 2

基于以上栈操作的示意图

基于对象的栈

创建一个Stack类最简单的方式是使用一个数组来存储元素。在处理大量数据的时候,我们同样需要评估如何操作数据是最高效的。

使用数组时,大部分方法的时间复杂度是O(n)。简单理解:O(n)的意思为我们需要迭代整个数组直到找到要找的那个元素,在最坏的情况下需要迭代数组的所有位置,其中的n代表数组的长度。数组越长,所需时间会更长。另外,数组是元素的一个有序集合,为保证元素的有序排列,会占用更多的内存空间。

使用JavaScript对象存储所有的栈元素,以实现可以直接获取元素,同时占用较少的内存空间,同时保证所有的元素按照我们的需要进行排列,遵循后进先出(LIFO)原则。

代码实现

  1. /**
  2. * 基于对象的Stack类
  3. * @author huxiaoshai
  4. */
  5. class Stack {
  6. // 初始化
  7. constructor () {
  8. this.items = {}
  9. this.count = 0
  10. }
  11. /**
  12. * push() 向栈中添加元素
  13. */
  14. push (element) {
  15. this.items[this.count] = element
  16. this.count++
  17. }
  18. /**
  19. * isEmpty() 判断是否为空
  20. */
  21. isEmpty () {
  22. return this.count === 0
  23. }
  24. /**
  25. * size() 返回栈的长度
  26. */
  27. size () {
  28. return this.count
  29. }
  30. /**
  31. * pop() 栈顶移除元素并返回
  32. */
  33. pop () {
  34. if (this.isEmpty()) {
  35. return undefined
  36. }
  37. this.count--
  38. let result = this.items[this.count]
  39. delete this.items[this.count]
  40. return result
  41. }
  42. /**
  43. * peek() 返回栈顶元素,如果为空则返回undefined
  44. */
  45. peek () {
  46. if (this.isEmpty()) {
  47. return undefined
  48. }
  49. return this.items[this.count - 1]
  50. }
  51. /**
  52. * clear() 清空栈数据
  53. */
  54. clear () {
  55. this.items = {}
  56. this.count = 0
  57. }
  58. /**
  59. * toString() 实现类似于数组结构打印栈内容
  60. */
  61. toString () {
  62. if (this.isEmpty()) {
  63. return ''
  64. }
  65. let objStr = `${this.items[0]}`
  66. for (let i = 1; i < this.count; i++) {
  67. objStr = `${objStr},${this.items[i]}`
  68. }
  69. return objStr
  70. }
  71. }

保护数据结构内部元素

私有属性

有时候我们需要创建供其他开发者使用的数据结构和对象时,我们希望保存内部元素,只有使用允许的方法才能修改内部结构。很不幸,目前JS是没有办法直接声明私有属性的,目前业内主要使用一下几种方式实现私有属性。

  1. 下划线命名约定

    1. class Stack {
    2. constructor () {
    3. this._items = {}
    4. this._count = 0
    5. }
    6. }

    这只是约定,一种规范,并不能实际保护数据

  2. 基于ES6的限定作用域Symbol实现类

    1. const _items = Symbol('stackItems')
    2. class Stack {
    3. constructor () {
    4. this[_items] = []
    5. }
    6. }

    假的私有属性,ES6新增的Object.getOwnPropertySymbols方法能够获取类里面声明的所有Symbols属性

  3. 基于ES6的WeakMap实现类

    1. /**
    2. * 使用WeekMap实现类的私有属性
    3. */
    4. const items = new WeakMap()
    5. console.log(items) // WeakMap { [items unknown] }
    6. class Stack {
    7. constructor () {
    8. items.set(this, [])
    9. }
    10. push (element) {
    11. const s = items.get(this)
    12. s.push(element)
    13. }
    14. pop () {
    15. const s = items.get(this)
    16. const r = s.pop()
    17. return r
    18. }
    19. toString () {
    20. const s = items.get(this)
    21. return s.toString()
    22. }
    23. }
    24. const stack = new Stack()
    25. stack.push(1)
    26. stack.push(2)
    27. stack.push(3)
    28. console.log(stack.toString()) // 1,2,3
    29. console.log(stack.items) // undefined

    使用该方式,items是Stack类里的私有属性,但是此种方式代码的可读性不强,而且在扩展该类时无法继承私有属性。

  4. ECMAScript类属性提案

    有一个关于JavaScript类中增加私有属性的提案。通过在属性前添加井号(#)作为前缀来声明私有属性。

  1. class Stack {
  2. #count = 0
  3. #items = []
  4. }

使用栈来解决问题

栈的实际应用非常广泛。在回溯问题中,它可以存储访问过的任务或路径、撤销的操作(后续会在讨论图和回溯问题时进一步详细讲解)。栈的使用场景有很多,如汉诺塔问题、平衡圆括号、计算机科学问题:十进制转二进制问题

  1. /**
  2. * decimalToBinary() 实现十进制转二进制的算法
  3. */
  4. function decimalToBinary (decNumber) {
  5. // 实例化栈数据结构
  6. const remStack = new Stack()
  7. let number = decNumber
  8. let rem;
  9. let binaryString = ''
  10. // 依次将获取的二进制数压入栈中
  11. while (number > 0) {
  12. rem = Math.floor(number % 2)
  13. remStack.push(rem)
  14. number = Math.floor(number / 2)
  15. }
  16. // 拼接要输出的二进制字符串
  17. while (!remStack.isEmpty()) {
  18. binaryString += remStack.pop().toString()
  19. }
  20. return binaryString
  21. }
  22. console.log(decimalToBinary(10)) // 1010
  23. console.log(decimalToBinary(23)) // 10111

后记

以上就是胡哥今天给大家分享的内容,喜欢的小伙伴记得收藏转发、点击右下角按钮在看,推荐给更多小伙伴呦,欢迎多多留言交流...

胡哥有话说,一个有技术,有情怀的胡哥!京东开放平台首席前端攻城狮。与你一起聊聊大前端,分享前端系统架构,框架实现原理,最新最高效的技术实践!

长按扫码关注,更帅更漂亮呦!关注胡哥有话说公众号,可与胡哥继续深入交流呦!

重读《学习JavaScript数据结构与算法-第三版》- 第4章 栈的更多相关文章

  1. 重读《学习JavaScript数据结构与算法-第三版》- 第5章 队列

    定场诗 马瘦毛长蹄子肥,儿子偷爹不算贼,瞎大爷娶个瞎大奶奶,老两口过了多半辈,谁也没看见谁! 前言 本章为重读<学习JavaScript数据结构与算法-第三版>的系列文章,主要讲述队列数据 ...

  2. 重读《学习JavaScript数据结构与算法-第三版》-第2章 ECMAScript与TypeScript概述

    定场诗 八月中秋白露,路上行人凄凉: 小桥流水桂花香,日夜千思万想. 心中不得宁静,清早览罢文章, 十年寒苦在书房,方显才高志广. 前言 洛伊安妮·格罗纳女士所著的<学习JavaScript数据 ...

  3. 重读《学习JavaScript数据结构与算法-第三版》- 第6章 链表(一)

    定场诗 伤情最是晚凉天,憔悴厮人不堪言: 邀酒摧肠三杯醉.寻香惊梦五更寒. 钗头凤斜卿有泪,荼蘼花了我无缘: 小楼寂寞新雨月.也难如钩也难圆. 前言 本章为重读<学习JavaScript数据结构 ...

  4. 重读《学习JavaScript数据结构与算法-第三版》- 第3章 数组(一)

    定场诗 大将生来胆气豪,腰横秋水雁翎刀. 风吹鼍鼓山河动,电闪旌旗日月高. 天上麒麟原有种,穴中蝼蚁岂能逃. 太平待诏归来日,朕与先生解战袍. 此处应该有掌声... 前言 读<学习JavaScr ...

  5. 学习JavaScript数据结构与算法 (二)

    学习JavaScript数据结构与算法 的笔记 包含第四章队列, 第五章链表 本人所有文章首发在博客园: http://www.cnblogs.com/zhangrunhao/ 04队列 实现基本队列 ...

  6. 学习JavaScript数据结构与算法 (一)

    学习JavaScript数据结构与算法 的笔记, 包含一二三章 01基础 循环 斐波那契数列 var fibonaci = [1,1] for (var i = 2; i< 20;i++) { ...

  7. 学习JavaScript数据结构与算法---前端进阶系列

    学习建议 1.视频学习---认知 建议:在中国慕课上找"数据结构"相关的视频教程.中国大学MOOC 推荐清华大学.北京大学.浙江大学的教程,可先试看,然后根据自身的情况选择视频进行 ...

  8. 学习Javascript数据结构与算法(第2版)笔记(1)

    第 1 章 JavaScript简介 使用 Node.js 搭建 Web 服务器 npm install http-server -g http-server JavaScript 的类型有数字.字符 ...

  9. 学习JavaScript数据结构与算法 2/15

    第一章 JavaScript简介 js不同于C/C++,C#,JAVA,不是强类型语言. 通常,代码质量可以用全局变量和函数的数量来考量(数量越多越糟).因此,尽可能避免使用全局变量. JS数据类型 ...

随机推荐

  1. 如何在vue中监听scroll,从而实现滑动加载更多

    首先需要明确3个定义: 文档高度:整个页面的高度 可视窗口高度:你看到的浏览器可视屏幕高度 滚动条滚动高度: 滚动条下滑过的高度 当 文档高度 = 可视窗口高度 + 滚动条高度  时,滚动条正好到底. ...

  2. 微信小程序开发--数据绑定

    一.单项数据绑定 <!-- index.wxml --> <view class="container"> <form> <input v ...

  3. Java的Hook线程及捕获线程执行异常

    import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.f ...

  4. centos 安装Python3 及对应的pip

    安装Python3安装Python依赖:yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqli ...

  5. 使用GDAL实现DEM的地貌晕渲图(二)

    1. 问题 之前我在<使用GDAL实现DEM的地貌晕渲图(一)>这篇文章里面讲述了DEM晕渲图的生成原理与实现,大体上来讲是通过计算DEM格网点的法向量与日照方向的的夹角,来确定该格网点的 ...

  6. Gym - 101194L World Cup 暴力

    World CupInput file: Standard InputOutput file: Standard OuptutTime limit: 1 second Here is World Cu ...

  7. Jsoup访问https网址异常SSLHandshakeException(已解决)

    爬取网页遇到的目标站点证书不合法问题. 使用jsoup爬取解析网页时,出现了如下的异常情况. javax.net.ssl.SSLHandshakeException: sun.security.val ...

  8. 查询表格——建立动态表格,使用ajax输入查询条件将后台数据查询出来以表格的形式展示出来

    建立动态表格,使用ajax将前台查询条件传给后台,并将查询结果以表格的形式展示出来. 页面的展示效果如下图所示: 第一步:查询条件的部分: 代码如下: <div class="text ...

  9. [git] 基础命令笔记

    --内容整理自廖雪峰的GIT教程-- git status 查看当前工作区状态,显示未跟踪的文件以及未上传的修改记录 git init 使当前文件夹变成Git可以管理的仓库 git add xxx 将 ...

  10. Java EE.JSP.内置对象

    JSP根据Servlet API 规范提供了某些内置对象,开发者不用事先声明就可以使用标准的变量来访问这些对象.JSP提供了九中内置对象:request.response.out.session.ap ...