【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的更多相关文章

  1. 【JavaScript数据结构系列】03-队列Queue

    [JavaScript数据结构系列]03-队列Queue 码路工人 CoderMonkey 转载请注明作者与出处 1. 认识队列Queue结构 队列,跟我们的日常生活非常贴近,我们前面举例了食堂排队打 ...

  2. 【JavaScript数据结构系列】00-开篇

    [JavaScript数据结构系列]00-开篇 码路工人 CoderMonkey 转载请注明作者与出处 ## 0. 开篇[JavaScript数据结构与算法] 大的计划,写以下两部分: 1[JavaS ...

  3. javascript数据结构与算法---栈

    javascript数据结构与算法---栈 在上一遍博客介绍了下列表,列表是最简单的一种结构,但是如果要处理一些比较复杂的结构,列表显得太简陋了,所以我们需要某种和列表类似但是更复杂的数据结构---栈 ...

  4. JavaScript数据结构与算法-栈练习

    栈的实现 // 栈类 function Stack () { this.dataStore = []; this.top = 0; // 栈顶位置 相当于length,不是索引. this.push ...

  5. 【JavaScript数据结构系列】04-优先队列PriorityQueue

    [JavaScript数据结构系列]04-优先队列PriorityQueue 码路工人 CoderMonkey 转载请注明作者与出处 ## 1. 认识优先级队列 经典的案例场景: 登机时经济舱的普通队 ...

  6. 【JavaScript数据结构系列】01-数组Array

    [JavaScript数据结构系列]01-数组Array 码路工人 CoderMonkey 转载请注明作者与出处 # [JavaScript数据结构系列] # 01-数组Array 数组: 是有序的元 ...

  7. JavaScript进阶系列02,函数作为参数以及在数组中的应用

    有时候,把函数作为参数可以让代码更简洁. var calculator = { calculate: function(x, y, fn) { return fn(x, y); } }; var su ...

  8. 【JavaScript数据结构系列】07-循环链表CircleLinkedList

    [JavaScript数据结构系列]07-循环链表CircleLinkedList 码路工人 CoderMonkey 转载请注明作者与出处 1. 认识循环链表 首节点与尾节点相连的,就构成循环链表.其 ...

  9. 【JavaScript数据结构系列】05-链表LinkedList

    [JavaScript数据结构系列]05-链表LinkedList 码路工人 CoderMonkey 转载请注明作者与出处 ## 1. 认识链表结构(单向链表) 链表也是线性结构, 节点相连构成链表 ...

随机推荐

  1. JSON Introduction

    理解 JSON(JavaScript Object Notation),一种轻量级的数据交换格式,基于JS的一个子集,但其数据格式与语言无关. 通俗来说,如果你是PHP,要和JS互相发送信息,那么这时 ...

  2. 疯子的算法总结(六) 复杂排序算法 ① 归并排序 merge_sort()

    归并排序采取了分治的思想,每次分别排左半边和右半边,不断递归调用自己,直到只有一个元素递归结束,开始回溯,调用merge函数,合并两个有序序列,再合并的时候每次给末尾追上一个最大int这样就不怕最后一 ...

  3. python(运算符)

    一.运算符 1.算数运算符 (1)加(+) 注意:字符串与整数之间不能进行相加,需要通过str()或int()进行转换数据类型 整数与整数相加 >>> 1 + 1 2 >> ...

  4. 蓝色展开收缩悬浮QQ客服代码

    放在我的博客首页上的的预览图: 在文章区的预览图如下: 代码如下: <div class="scrollsidebar" id="scrollsidebar&quo ...

  5. Android EventBus踩坑,Activity接收不了粘性事件。

    注解问题 EventBus 的 粘性事件,可以让 成功注册后的 Activity.Fragment 后再接收处理 这一事件. 但是今晚写代码时,突然发现粘性事件,发送不成功了.??? 具体情况是:我在 ...

  6. Spring Boot Actuator H2 RCE复现

    0x00 前言 Spring Boot框架是最流行的基于Java的微服务框架之一,可帮助开发人员快速轻松地部署Java应用程序,加快开发过程.当Spring Boot Actuator配置不当可能造成 ...

  7. airtest+poco多脚本、多设备批处理运行测试用例自动生成测试报告

    一:主要内容 框架功能及测试报告效果 airtest安装.环境搭建 框架搭建.框架运行说明 airtest自动化脚本编写注意事项 二:框架功能及测试报告效果 1. 框架功能: 该框架笔者用来作为公司的 ...

  8. E. Count The Blocks

    E. Count The Blocks 这是一个计数题,又把我卡自闭了...之前也碰到过类似的题目,这次居然还没有写出来,感觉自己还是太菜了,加油补题吧. 题目大意: 给你一个数字 \(n\),代表的 ...

  9. Django 配置JWT认证方式

    1. 安装 rest_framework + djangorestframework_simplejwt 安装djangorestframework_simplejwt :pip install dj ...

  10. 最简单的手机预览WEB移动端网页的方法

    网上看了很多关于该问题的解决办法,各种各样的都有,个人也测试了一些, 最后总结出一个最简单且实用的方法. 1.安装nodejs node官网下载对应版本的nodejs,安装好了之后,在node.js执 ...