【JavaScript数据结构系列】02-栈Stack
【JavaScript数据结构系列】02-栈Stack
码路工人 CoderMonkey
转载请注明作者与出处
## 1. 认识栈结构
栈是非常常用的一种数据结构,
与数组同属线性数据结构,
不同于数组的是它是一种受限的线性结构。
画一张图来说明:
如上图所示,
- 最新入栈的元素/最底下的元素,为栈底
- 最后一个/最上面的元素,为栈顶
- 最后一个入栈元素最先出栈(LIFO原则)
- 只能操作栈顶
- 添加元素叫:进栈/压栈/入栈
- 删除元素叫:出栈/退栈
## 2. 栈的应用:
- 函数调用栈
- 文本编辑器中的撤销与重做
等。
3. 栈的实现
注:
ES6 版的代码实现请查看 npm 包 data-struct-js 代码
代码在 Github/Gitee
3.1 常用方法
方法 | 描述 |
---|---|
push(element) | 添加元素到栈顶 |
pop() | 删除栈顶元素 |
peek() | 查看栈顶元素 |
isEmpty() | 检查是否为空栈 |
size() | 检查栈容量 |
clear() | 清空栈 |
toString() | 字符串化 |
3.2 常用方法的代码实现
栈的实现可以基于数组,也可以基于链表,
这里我们用基于数组来实现一下。
首先,写出Stack的构造函数
function Stack() {
this.__items = []
}
3.2.1 push
实现分析:
向数组尾部添加元素,同JS数组操作
function Stack() {
this.__items = []
Stack.prototype.push = function(element) {
return this.__items.push(element)
}
}
3.2.2 pop
实现分析:
删除/弹出数组最后一个元素,同JS数组操作
function Stack() {
this.__items = []
Stack.prototype.pop = function() {
return this.__items.pop()
}
}
3.2.3 peek
实现分析:
查看栈顶即数组最后一个元素
function Stack() {
this.__items = []
Stack.prototype.peek = function() {
if(!this.__items.length) return null
return this.__items[this.__items.length-1]
}
}
3.2.4 isEmpty
实现分析:
只要看内部数组元素个数是否为0
function Stack() {
this.__items = []
Stack.prototype.isEmpty = function() {
return this.__items.length === 0
}
}
3.2.5 size
实现分析:
返回内部数组元素个数
function Stack() {
this.__items = []
Stack.prototype.size = function() {
return this.__items.length
}
}
3.2.6 clear
实现分析:
清空内部数组
function Stack() {
this.__items = []
Stack.prototype.clear = function() {
this.__items.length = 0
}
}
3.2.7 toString
实现分析:
将内部数组用 join 连结
function Stack() {
this.__items = []
Stack.prototype.toString = function() {
return this.__items.join(' ')
}
}
完整代码如下:
// 栈
function Stack() {
this.__items = []
// 入栈
Stack.prototype.push = function (element) {
return this.__items.push(element)
}
// 出栈
Stack.prototype.pop = function () {
return this.__items.pop()
}
// 查看栈顶
Stack.prototype.peek = function () {
if (!this.__items.length) return null
return this.__items[this.__items.length - 1]
}
// 是否为空栈
Stack.prototype.isEmpty = function () {
return this.__items.length === 0
}
// 获取栈大小/容量/元素个数
Stack.prototype.size = function () {
return this.__items.length
}
// 清空栈
Stack.prototype.clear = function() {
this.__items.length = 0
}
// 字符串值
Stack.prototype.toString = function () {
return this.__items.join(' ')
}
}
3.3 下面我们测试一下:
// ---------------------------------------------
// Test
// ---------------------------------------------
var s = new Stack()
for(var i = 0; i < 5; i++){
s.push(i)
}
console.log('isEmpty: ',s.isEmpty()) // isEmpty: false
console.log('size: ',s.size()) // size: 5
console.log(s.toString()) // 0 1 2 3 4
while(s.size()) {
console.log(`pop: `, s.pop()) // 4 3 2 1 0
}
console.log('isEmpty: ',s.isEmpty()) // isEmpty: true
console.log('size: ',s.size()) // size: 0
我们得到了符合预期的结果。
在上面的实现中,没有考虑复杂类型时的引用传递问题,
也没有遍历方法,这些我们将在后面补充完善。
4. 思考题
4.1 判断哪个不是可能的出栈顺序?()
有六个元素`6,5,4,3,2,1`依次进栈,下列哪一个不是合法的出栈顺序?
- A. 5 4 3 6 1 2
- B. 4 5 3 2 1 6
- C. 3 4 6 5 2 1
- D. 2 3 4 1 5 6
这个选择题还是非常简单的,
满足先进后出画图一试答案就出来了。
下面利用栈结构实现十进制转二进制。
比起网上的其它例子,
这里稍微复杂了的一点在于,
不仅仅针对正整数,考虑了负数。
4.2 十进制整数转二进制的方法实现
4.2.1 转换的数学方法
将一个十进制的数转为二进制,
- 将这个数与2取模,记录余数,将商用于下一次计算
- 重复上一步,直到商为0
- 将得到的余数由后向前连接起来,即为所求二进制结果
举例:计算8的2进制值是多少
原十进制值 | 取模 | 等于 | 余数 |
---|---|---|---|
8 | 2 | 4 | 0 |
4 | 2 | 2 | 0 |
2 | 2 | 1 | 0 |
1 | 2 | 0 | 1 |
这样,得到的二进制就是:1000
(也即 0000 1000)
负数时的规则:反码后加1补码
所以 -8 的二进制计算过程为:
- 0000 1000取反:1111 0111
- 补码:1111 1000
4.2.2 转换的代码实现
基于栈的实现,这里就不重复贴 Stack.js
的代码了。
代码实现分析:
- 等于0的情况,直接返回0
- 大于0的情况,按照我们上面列出的转换方法
- 与2取模,保存入栈,直到商为0
- 依序出栈,拼接结果并返回
- 小于0的情况,比起以上两种情况来说最复杂
- 先乘以-1转为正整数,再按照大于0的情况进行取模处理
- 取模结果要取反(即0变1,1变0),然后保存入栈
- 计算完,依序出栈,得到中间结果
- 将上面得到的结果值 +1 进行补码
- 再在首位前加上一位1来表示负数
- TODO:其实还需要完善一点,空位用1补足8位(或其它可能的位数)
// ---------------------------------------------
// decimal to binary
// ---------------------------------------------
function dec2bin(decNum) {
if(!decNum) return 0
var stack = new Stack()
var minus = decNum < 0
if(minus) {
decNum *= -1
while(decNum) {
var temp = decNum % 2
switch(temp) {
case 0:
temp = 1
break
case 1:
temp = 0
break
}
stack.push(temp)
decNum = parseInt(decNum / 2)
}
} else {
while(decNum) {
stack.push(decNum % 2)
decNum = parseInt(decNum / 2)
}
}
var result = ''
while(!stack.isEmpty()) {
result += stack.pop()
}
if(minus) {
// 补码
for(var i=result.length-1;i>=0;i--) {
var arrTemp = result.split('')
switch(result[i]) {
case '0':
arrTemp[i] = 1
break
case '1':
arrTemp[i] = 0
break
}
result = arrTemp.join('')
}
result = '1' + result
}
return result
}
var ret = dec2bin(8)
console.log(' 8 => ', ret) // 1000
ret = dec2bin(-8)
console.log('-8 => ', ret) // 1 1000
以上就是完整代码,运行一下试试吧。
基于 ES6 实现的 JavaScript 数据结构,
虽然这个小轮子很少会被使用,
也许对于初学者学习 JavaScript 会有点帮助。
只要简单 install 一下即可,感兴趣的话还可以去
GitHub / Gitee 看源码。(Star 表支持~)
npm install data-struct-js --save-dev
https://github.com/CoderMonkie/data-struct-js
https://gitee.com/coder-monkey/data-struct-js
最后,感谢您的阅读和支持~
-end-
【JavaScript数据结构系列】02-栈Stack的更多相关文章
- 【JavaScript数据结构系列】03-队列Queue
[JavaScript数据结构系列]03-队列Queue 码路工人 CoderMonkey 转载请注明作者与出处 1. 认识队列Queue结构 队列,跟我们的日常生活非常贴近,我们前面举例了食堂排队打 ...
- 【JavaScript数据结构系列】00-开篇
[JavaScript数据结构系列]00-开篇 码路工人 CoderMonkey 转载请注明作者与出处 ## 0. 开篇[JavaScript数据结构与算法] 大的计划,写以下两部分: 1[JavaS ...
- javascript数据结构与算法---栈
javascript数据结构与算法---栈 在上一遍博客介绍了下列表,列表是最简单的一种结构,但是如果要处理一些比较复杂的结构,列表显得太简陋了,所以我们需要某种和列表类似但是更复杂的数据结构---栈 ...
- JavaScript数据结构与算法-栈练习
栈的实现 // 栈类 function Stack () { this.dataStore = []; this.top = 0; // 栈顶位置 相当于length,不是索引. this.push ...
- 【JavaScript数据结构系列】04-优先队列PriorityQueue
[JavaScript数据结构系列]04-优先队列PriorityQueue 码路工人 CoderMonkey 转载请注明作者与出处 ## 1. 认识优先级队列 经典的案例场景: 登机时经济舱的普通队 ...
- 【JavaScript数据结构系列】01-数组Array
[JavaScript数据结构系列]01-数组Array 码路工人 CoderMonkey 转载请注明作者与出处 # [JavaScript数据结构系列] # 01-数组Array 数组: 是有序的元 ...
- JavaScript进阶系列02,函数作为参数以及在数组中的应用
有时候,把函数作为参数可以让代码更简洁. var calculator = { calculate: function(x, y, fn) { return fn(x, y); } }; var su ...
- 【JavaScript数据结构系列】07-循环链表CircleLinkedList
[JavaScript数据结构系列]07-循环链表CircleLinkedList 码路工人 CoderMonkey 转载请注明作者与出处 1. 认识循环链表 首节点与尾节点相连的,就构成循环链表.其 ...
- 【JavaScript数据结构系列】05-链表LinkedList
[JavaScript数据结构系列]05-链表LinkedList 码路工人 CoderMonkey 转载请注明作者与出处 ## 1. 认识链表结构(单向链表) 链表也是线性结构, 节点相连构成链表 ...
随机推荐
- NodeJs mysql 开启事务
如题:node后台使用mysql数据库,并使用事务来管理数据库操作. 这里主要讲一个事务的封装并写了一个INSERT 插入操作. code: 基础code: db.config.js const my ...
- How to get binary string from ArrayBuffer?
https://stackoverflow.com/questions/16363419/how-to-get-binary-string-from-arraybuffer https://stack ...
- shell之路 shell核心语法【第一篇】shell初识
shell简介 1.Shell是Unix的脚本语言,是与 Unix/Linux 交互的工具,shell使用的熟练程度反映了用户对Unix/Linux使用的熟练程度 2.Shell是系统命令+程序逻辑的 ...
- TCP 可靠传输
TCP报文段首部 序号: TCP是面向字节流的.在一个TCP连接中传送的字节流中的每一个字节都按顺序编号.整个要传送的字节流的起始序号必须在连接建立时设置.首部中的序号字段值则指的是本报文段所发送的数 ...
- golang 容器的学习与实践
golang 提供了几个简单的容器供我们使用,本文在介绍几种Golang 容器的基础上,实现一个基于Golang 容器的LRU算法. 容器介绍 Golang 容器位于 container 包下,提供了 ...
- E. Paint the Tree 树形dp
E. Paint the Tree 题目大意:给你一棵树,每一个点都可以染k种颜色,你拥有无数种颜色,每一种颜色最多使用2次,如果一条边的两个节点拥有同一种颜色,那么就说 这条边是饱和的,一个树的价值 ...
- C. Four Segments 前缀后缀
C. Four Segments 这种分成了三个节点一般都可以处理一下前缀处理一下后缀,或者处理一下前面的这个点,处理一下后面的这个点,然后再枚举中间这个点. 如果和中间这个点有关的,那么就可以换一下 ...
- 【GISER&&规划】我这二三年
从从参加工作到现在,已经接近三年了.在这不长不短的时间里,我的职业规划犹如正余弦函数一样变化,一直游离在前端和后端之间. 第一年入职,被安排维护和拓展一套基于JAVA实现的地图瓦片生产工艺程序,不算复 ...
- Java return 关键字
一.基本概念 return一方面用在循环语句中来结束循环,另一方面用来终止函数的执行或者退出类的方法,并把控制权返回该方法的调用者.如果方法有返回类型,则return的返回该类型的值:如果没有返回值, ...
- MYSQL连接端口被占引入文件路径错误
今天早上打算本地win7机器上用Wampserver搭建PHP环境,把自己的程序配置上去.下载最新的wampserver 3.0.6版本安装后,发现mysql一直无法运行,以为是wampserver版 ...