本文由图雀社区认证作者 神奇的程序员 写作而成,图雀社区将连载其TypeScript 实战算法系列,点击阅读原文查看作者的掘金链接,感谢作者的优质输出,让我们的技术世界变得更加美好?

前言

栈作为一种数据结构,它可以应用在很多地方,当你需要经常获取刚存放进去的数据时,那么栈这种数据结构将是你的首选。
栈的实现方式一般有两种:数组实现和对象实现,这两种实现方式最终实现的功能都是一样的,但是在性能上却有着很大的差别。
本文将详细讲解这两种实现方式的差异并用TypeScript将其实现,欢迎各位感兴趣的开发者阅读本文。

数组实现栈

本文讲解的是栈用代码的实现,如果对栈这种数据结构还不是很了解的话,可以移步我的另一篇文章:栈与队列

实现思路

栈的核心思想为后进先出(LIFO),那么我们可以用数组来描述栈。
接下来,我们来看下,一个栈都需要具备哪些功能:

  • 入栈,添加一个新元素至栈顶(数组的末尾)。
  • 出栈,将栈顶的元素移除并返回被移除的元素。
  • 获取栈顶元素,获取当前栈顶元素返回。
  • 判断栈是否为空,判断栈(数组)内是否有数据。
  • 清空栈,移除栈内所有的元素。
  • 获取栈大小,返回栈里的元素个数。
  • 输出栈内数据,将栈中的所有元素以字符串的形式返回。

我们分析完栈都需要具备哪些功能后,发现数组中提供了很多现成的API可以实现上述功能,接下来,跟大家分享下上述功能的实现思路。

  • 入栈(push),可以使用数组的push方法直接往数组的末尾添加元素。
  • 出栈(pop),可以使用数组的pop方法直接移除栈中的元素,该方法会返回当前被移除的元素。
  • 栈顶元素(peek),可以通过数组的长度-1获取到数组中的最后一个元素。
  • 栈是否为空(isEmpty),可以通过判断数组的长度是否为0来实现。
  • 清空栈(clear),可以将数组直接赋值为空或者调用出栈方法直至栈中的数据为空。
  • 栈大小(size),可以返回数组的长度。
  • 输出栈内数据,可以调用数组的toString方法将数组转换为字符串。

实现代码

有了实现思路后,我们就可以将上述实现思路转换为代码了。

  • 新建一个Stack.ts文件
  • 定义栈并规定其类型
private items: any[];
  • 在构造器中初始化栈
constructor() {this.items = [];    }
  • 根据实现思路实现栈中的函数
// 入栈    push(item:any) {this.items.push(item);    }// 出栈    pop() {return this.items.pop();    }// 返回栈顶元素    peek() {return this.items[this.items.length - 1];    }// 判断栈是否为空    isEmpty() {return this.items.length === 0;    }// 清空栈栈内元素    clear() {this.items = [];    }// 获取栈内元素数量    size():number{return this.items.length;    }// 将栈内元素转为字符串    toString(){return this.items.toString();    }

完整代码请移步:Stack.ts

编写测试代码

上述代码我们实现了一个栈,接下来我们往栈中添加几条数据,测试栈内的方法是否正确执行。

  • 新建一个StackTest.js文件
  • 实例化一个栈
const stack = new Stack();
  • 测试栈内方法是否正确执行
// 入栈stack.push("第一条数据");stack.push("第二条数据");// 出栈stack.pop();// 返回栈顶元素console.log(stack.peek());// 查看栈大小console.log(stack.size());// 判断栈是否为空console.log(stack.isEmpty());// 返回栈内所有元素console.log(stack.toString())// 清空栈stack.clear()

完整代码请移步:StackTest.js
执行结果如下

对象实现栈

实现一个栈最简单的方式是通过数组存储每一个元素。在处理大量数据时,我们需要评估如何操作数据是最高效的。
在使用数组时,大部分方法的时间复杂度都为O(n),我们需要迭代整个数组直至找到目标元素,在最坏的情况下我们需要迭代数组的每一个位置。数组是元素的一个有序集合,为了保证元素排列有序,它会占用更多的内存空间。
如果我们可以直接获取元素,占用更少的内存空间,并且仍然保证所有元素都按照我们的需要进行排列,就属于最优解决方案了。

实现代码

我们可以使用一个对象来存储所有的栈元素,保证它们的顺序并且遵循LIFO原则。接下来我们来看看如何使用对象来实现栈。

  • 新建一个ObjStack.ts文件
  • 定义栈对象结构
interface StackObj {    [propName: number] : any;}
  • 定义栈并规定其类型,count用于记录栈的大小。
private items: StackObj;private count: number;
  • 在构造器中初始化栈相关变量
this.items = {};this.count = 0;
  • 入栈,当前栈的大小为新元素的key。
push(item: any) {this.items[this.count] = item;this.count++;}
  • 出栈,当前栈大小-1,取出栈顶元素,删除栈顶元素,返回取出的栈顶元素
pop() {if(this.isEmpty()){return undefined;    }this.count--;const result = this.items[this.count];delete this.items[this.count];console.log(this.items);return result;}
  • 返回栈顶元素,以当前栈大小-1为key获取其对应的value值。
peek() {if(this.isEmpty()){return undefined;    }return this.items[this.count - 1];}
  • 判断栈是否为空,清空栈内元素,获取栈内元素数量
// 判断栈是否为空isEmpty() {return this.count === 0;   }// 清空栈内元素clear() {this.items = [];this.count = 0;}// 获取栈内元素数量size():number{return this.count;}
  • 将栈内元素转为字符串,遍历当前栈对象中的数据,将栈中的数据用逗号拼接并返回。
toString(){if (this.isEmpty()){return "";    }let objString = `${this.items[0]}`;for (let i = 1; i < this.count; i++){        objString = `${objString},${this.items[i]}`    }return objString;}

完整代码请移步:ObjStack.ts

编写测试代码

上述代码我们用对象实现了一个栈,接下来我们往栈中添加几条数据,测试栈内的方法是否正确执行。

  • 新建一个StackObjTest.js文件
  • 实例化一个栈
const stack = new ObjStack();
  • 测试栈内方法是否正确执行
// 入栈stack.push("第一条数据");stack.push("第二条数据");// 出栈stack.pop();// 返回栈顶元素console.log(stack.peek());// 查看栈大小console.log(stack.size());// 判断栈是否为空console.log(stack.isEmpty());// 返回栈内所有元素console.log(stack.toString())// 清空栈stack.clear()

完整代码请移步:StackObjTest.js
执行结果如下

二者的区别

数组大部分方法的时间复杂度都为O(n),数组中的元素是一个有序集合,为了保证元素排列有序,它会占用更多的内存空间。
对象可以通过key直接访问到目标元素时间复杂度为O(1),我们可以直接目标元素进行操作,速度明显比数组快了很多倍。
接下来,我们通过一个实例来看看这两者在执行速度上的差异。

十进制转二进制

把十进制转为二进制,需要将该十进制除以2并对商取整,直到结果是0为止。

  • 声明一个函数参数为一个十进制数
const decimalToBinaryStack = function (decNumber) {}
  • 函数内部声明一个变量,用于接收当前传进来的参数进行除法运算后得到的值。
// 传进来的十进制数let number = decNumber;
  • 函数内部实例化一个栈,用于保存模运算后得出的值。
  • 函数内部声明两个变量,用户保存当前模运算的值和最终生成的二进制字符串
// 余数let rem;// 二进制结果let binaryString = "";
  • while循环,判断当前参数进行除法运算后得到的值是否为0,如果不为0就对当前结果进行模运算,将模运算得到的值入栈,对当前结果进行除法运算,直至当前结果为0。
while (number > 0) {// 模运算    rem = Math.floor(number % 2);// 将余数入栈    stack.push(rem);// 当前十进制结果除以二number = Math.floor(number / 2);}
  • while循环,将栈中的数据取出拼接到二进制结果字符串中去
while (!stack.isEmpty()) {    binaryString += stack.pop().toString();}
  • 返回二进制结果字符串
return binaryString;

完整代码请移步:Examples.js

实现代码如上所述,唯一不同的就是一个使用的是对象栈一个使用的数组栈,接下来我们来看下不同栈的运行时间差距。

写在最后

  • 公众号无法外链,如果文中有链接,可点击下方阅读原文查看?

❤️爱心三连击

1.看到这里了就点个在看支持下吧,你的在看是我创作的动力。

2.关注公众号图雀社区「带你一起学优质实战技术教程」

3.特殊阶段,带好口罩,做好个人防护。

4.添加微信【little-tuture】,拉你进技术交流群一起学习。

● 前端基础进阶(一):JavaScript 内存空间详细图解

● 最简实现Promise,支持异步链式调用(20行)

● 你不知道的 Webpack(4000字,手写源码)

·END·

图雀社区

汇聚精彩的免费实战教程

关注公众号回复 z 拉学习交流群

喜欢本文,点个“在看”告诉我

freemarker 数组转字符串_TypeScript 实战算法系列(一):实现数组栈与对象栈相关推荐

  1. 算法系列15天速成——第十天 栈

    原文:算法系列15天速成--第十天 栈 今天跟大家聊聊栈,在程序设计中,栈的使用还是非常广泛的,比如有"括号匹配问题","html结构匹配问题". 所以说掌握了 ...

  2. 涤生校招算法系列5:数组基本操作必掌握

         校招不同于社招,不管是科班的大数据/计算机相关类专业的,还是其他专业转行大数据的小伙伴.同样大数据校招面试也是更看重基础(尤其是中大厂),校招不仅需要掌握大数据相关技术,还需要掌握一些基础知 ...

  3. php和c语言的字符数组中,字符数组和字符串的区别,C语言字符数组和字符串区别详解...

    C 语言中并不存在字符串这个数据类型,而是使用字符数组来保存字符串.那么,字符数组就一定是字符串吗? 对于这个问题,大多教科书中的回答是"是".其实不然,字符数组和字符串是完全不相 ...

  4. 字符数组和字符串的区别,C语言字符数组和字符串区别详解

    C 语言中并不存在字符串这个数据类型,而是使用字符数组来保存字符串.那么,字符数组就一定是字符串吗? 不一定,字符数组和字符串千万不要混淆.字符串是一种特殊的字符数组,并且C语言提供了大量适用于字符串 ...

  5. php key数组转字符串,学习猿地-php怎么将数组转化成字符串

    php将数组转化成字符串的方法:首先创建一个PHP示例文件:然后定义一个数组数据为"$arr":接着通过"implode($arr);"方法将该数组转化成字符串 ...

  6. 看动画学算法系列之:后缀数组suffix array

    文章目录 简介 后缀数组的定义 后缀数组的创建流程 在后缀数组中查找某个字符串 创建LCP 后缀数组和后缀树的比较 简介 在之前的文章中,我们讲到了后缀树和它的一些特性.后缀树主要用来做模式匹配中,比 ...

  7. es6 数组去重_《前端算法系列》数组去重

    虽然算法在前端开发中很少会得以使用,但是了解常用的算法,熟悉各种算法的性能和优劣,将会让你在前端的道路上走的更远. 前言 文中所有代码位于位于此代码仓库中,大家可以下载代码进行学习.推敲和改进.另,如 ...

  8. 树状数组求逆序对_算法系列之-数组中的逆序对

    题目来源 剑指offer 01 题目描述 在数组中如果前一个数字大于后一个数字,则称为这个数字组合组成一个逆序对.输入一个数组,求所有的逆序对的总数. 如 数组 {7,5,6,4} 则它的逆序对是 ( ...

  9. 去掉数组最后一个元素_leetcode 34. 在排序数组中查找元素的第一个和最后一个位置每天刷一道leetcode算法系列!...

    作者:reed,一个热爱技术的斜杠青年,程序员面试联合创始人 前文回顾: leetcode1. 两数之和--每天刷一道leetcode系列! leetcode2. 两数相加--每天刷一道leetcod ...

最新文章

  1. C和C++安全编码笔记:总结
  2. Struts2文件上传方式与上传失败解决方式
  3. 白月黑羽教python excel_发布程序
  4. kotlin集合操作符——映射操作符
  5. python怎么创建一个二维数组_python 创建二维数组的方法
  6. git push -u origin master和git push 远程主机名 本地分支名:远程分支名作用
  7. 【操作系统】进程与线程
  8. Shell命令-文件及内容处理之sort、uniq
  9. OSSIM中主动与被动探测工具(arpwatch+p0f+pads)组合应用
  10. 蓝桥杯 基础练习 字母图形
  11. Mac与Windows或Linux的键鼠共享神器Synergy
  12. NV12转BGR24算法总结
  13. 【HTML+CSS+JS】模仿QQ登录界面
  14. xlsx如何查找替换_Excel中如何使用通配符查找和替换
  15. Hive3第五章:函数
  16. C语言程序设计选题参考
  17. 儿童节html5小游戏,六一儿童节室内小游戏有哪些
  18. 消消乐android 源代码,【消消乐】源代码
  19. iOS APP上线App Store流程(包括.p12导出)
  20. 植物大战僵尸全明星服务器维修多长时间,植物大战僵尸全明星常见问题怎么解决?...

热门文章

  1. linux php 中文文件名乱码,linux文件名乱码
  2. php现实的九九乘法,php趣味编程 - php 输出九九乘法
  3. 7价 半导体掺杂_模电总结第一章:常用半导体器件
  4. java murmurhash实现_一致性哈希算法与Java实现
  5. oracle 添加默认值列,Oracle 11g增加列,并带默认值的新特性
  6. 光纤熔接盒盘线方法_唐品小课堂光纤色谱
  7. php连接access带密码,phpadodb连接带密码access数据库实例,测试成功
  8. php接收post写入文件,PHP中Post和Get获取数据写入文件中
  9. mysql查询无主键的表的方法:
  10. glance查看进程内存使用过大问题