Javascript数据结构与算法--栈的实现与用法
栈数据结构
栈是一种遵从后进先出(LIFO)原则的有序集合。新添加的或者待删除的元素都保存在栈的同一端,称作栈顶,另一端就叫栈底。在栈里,新元素都靠近栈顶,旧元素都接近栈底。
我们在生活中常能看到栈的例子。整齐堆起来的书,厨房堆起的盘子等
栈也被用在编程语言的编译器和内存中保存变量、方法调用等。
我们可以选择不同的数据结构来保存栈中的元素,在这里,我们选择数组来保存栈中的元素。
/**
* 使用es6中的Class语法来编写类:栈
* 此栈使用数组来保存元素
*/
class Stack {
constructor() {
this.items = [];
}
/**
* 添加一个(或几个)新元素到栈顶
* @param {*} element 新元素
*/
push(element) {
this.items.push(element)
}
/**
* 移除栈顶的元素,同时返回被移除的元素
*/
pop() {
return this.items.pop()
}
/**
* 返回栈顶的元素,不对栈做任何修改(这个方法不会移除栈顶的元素,仅仅返回它)
*/
peek() {
return this.items[this.items.length - 1]
}
/**
* 如果栈里没有任何元素就返回true,否则返回false
*/
isEmpty() {
return this.items.length === 0
}
/**
* 移除栈里的所有元素
*/
clear() {
this.items = []
}
/**
* 返回栈里的元素个数。这个方法和数组的length属性很类似
*/
size() {
return this.items.length
}
/**
* 返回以字符串形式输出的栈
*/
toString() {
return this.items.toString()
}
/**
* 返回以数组形式输出的栈
*/
toArray() {
return this.items
}
}
栈的用法
进制转换
更多详情请查看源码
在计算机里所有的内容都是二进制数字表示的(0和1),而我们生活中主要用到十进制,还有16进制等。那么就需要进制转换。我们可以利用栈来实现转换。
/**
* 10进制数转换为其他16进制以内进制的数
* @param {*} decNumber 需要转换的数
* @param {Int32Array} hex 进制数
*/
function hexConverter(decNumber, hex) {
let remStack = new Stack()
let rem = 0
let baseString = ''
let digits = '0123456789ABCDEF' //进制取数
if (hex < 2 || hex > 16) {
return '只转换大于二进制小于十六进制之间的进制'
}
while (decNumber > 0) {
rem = Math.floor(decNumber % hex) // 求模运算
remStack.push(rem)
decNumber = Math.floor(decNumber / hex) // 除运算
}
while (!remStack.isEmpty()) {
baseString += digits[remStack.pop()] // 取出栈中的数据对应于进制数的表示数
}
return baseString
}
回文判断
更多详情请查看源码
正读反读都相同的字符序列称为回文,例如“abccba”、“abcba”、“12321”、“123321”。
回文判断有很多种方法,在这里,我们可以采用先入栈后出栈的方法,来比较入栈之前,和出栈之后两个字符串是否相同。
空字符串到底是不是回文呢,有点疑惑? 我这里定义为不是回文。
/**
* 判断字符串是否为回文
* @param {String} str 要判断的字符串
*/
function palindrome(str) {
// 非string类型的 或者 空字符串 直接判断不是回文
if (typeof (str) !== 'string' || str.length === 0) {
return false
}
let stack = new Stack()
let oStr = str.toLocaleLowerCase()
let nStr = ''
for (let i = 0; i < str.length; i++) {
stack.push(str[i])
}
while (!stack.isEmpty()) {
nStr += stack.pop().toLocaleLowerCase()
}
if (nStr === oStr) {
// return `输入的字符串【{$oStr}】是回文`
return true
} else {
// return `输入的字符串【{$oStr}】不是回文`
return false
}
}
平衡括号
更多详情请查看源码
如果一个括号序列包含完整的左右括号对,则称为平衡括号序列。如:"{[()]}","", "({})", "{()}"都是平衡括号,而"{()[]", ")"则不是平衡括号。
括号只有三种()/[]/{}
,每种分别有左右括号。我们可以这样操作:遇到左括号,左括号入栈,遇到右括号,取出栈中最后一个括号来比对的方式来判断是否相等平衡。
/**
* 判断括号序列是否平衡,空序列也算是平衡
* @param {String} brackets 括号序列
*/
function balanceBracket(brackets) {
if (typeof (brackets) !== 'string') {
return false
}
let left = '([{'
let right = ')]}'
let num = 0 // 括号的对数
let stack = new Stack()
for (let i = 0; i < brackets.length; i++) {
if (right.indexOf(brackets[0]) > -1) {
return false
}
if (left.indexOf(brackets[i]) > -1) {
stack.push(brackets[i])
num++
} else {
if (right.indexOf(brackets[i]) > -1) {
let topBracket = stack.pop()
let rightSort = right.indexOf(brackets[i])
let leftSort = left.indexOf(topBracket)
if (rightSort !== leftSort) {
return false
}
}
}
}
if (!stack.isEmpty()) return false // 2019-5-30 更新,考虑情况 [[[()
return `是平衡括号序列。有${num}对括号`
}
汉诺塔
更多详情请查看源码
有三根相邻的柱子,标号为A,B,C。A柱子上从下到上按金字塔状叠放着n个不同大小的圆盘,要把所有圆盘移动到B柱子上。
要求:
- 每次只能移动一个圆盘。
- 每根柱子上的圆盘,下面的都比上面的大。
问题:
请问至少需要移动多少次圆盘?每次移动的步骤是怎样的?
let num = 0 // 记录移动的次数
/**
* 记录圆盘移动的过程
*
* 这里的思路,一直在循环做一件事情。
* 把原始柱子上的圆盘分为两部分,最大和其它。
* 第一回合,将其它移动到辅助柱子上,将最大的移动到目标柱子上,再将其它移动到目标柱子上
* 第二回合,将其它移动到辅助柱子上,将最大的移动到目标柱子上,再将其它移动到目标柱子上
* ...
* 第2 ** n - 1回合,将其它移动到辅助柱子上,将最大的移动到目标柱子上,再将其它移动到目标柱子上
*
* 但是,这里源柱子、辅助柱子和目标柱子会随着其它盘而变动。
* 其它盘在哪个柱子上,哪根柱子就是源柱子。
* @param {Int32Array} plates 圆盘个数
* @param {Array} source 源柱子
* @param {Array} helper 辅助柱子
* @param {Array} dest 目的地柱子
* @param {String} sourceName 源柱子的名字
* @param {String} helperName 辅助柱子的名字
* @param {String} destName 目的地柱子的名字
* @param {Array} moves 步骤存储器,存储每一步的流程
*/
function moveOfHanoi(
plates,
source,
helper,
dest,
sourceName,
helperName,
destName,
moves = []
) {
if (plates <= 0) {
return moves
} else if (plates === 1) {
// 弹出源柱子上剩下的最大圆盘,并将其压入目标柱子
dest.push(source.pop())
num++
let sourceArr = source.toString()
let helperArr = helper.toString()
let destArr = dest.toString()
let movestr = `第 ${num} 步,将圆盘 ${plates} 从 ${sourceName} 移至 ${destName}; ${sourceName}: [${sourceArr}],${helperName}: [${helperArr}],${destName}: [${destArr}]`
moves.push(movestr)
} else {
moveOfHanoi(
plates - 1,
source,
dest,
helper,
sourceName,
destName,
helperName,
moves
)
// 弹出源柱子上剩下的最大圆盘,并将其压入目标柱子
dest.push(source.pop())
num++
let sourceArr = source.toString()
let helperArr = helper.toString()
let destArr = dest.toString()
let movestr = `第 ${num} 步,将圆盘 ${plates} 从 ${sourceName} 移至 ${destName}; ${sourceName}: [${sourceArr}],${helperName}: [${helperArr}],${destName}: [${destArr}]`
moves.push(movestr)
moveOfHanoi(
plates - 1,
helper,
source,
dest,
helperName,
sourceName,
destName,
moves
)
}
return moves
}
/**
* 汉诺塔
* 记录每一次圆盘移动的动作。从${源柱子}到${目标柱子}
* @param {Int32Array} plates 圆盘的个数
* @param {String} sourceName 源柱子的名称
* @param {String} helperName 辅助柱子的名称
* @param {String} destName 目标柱子的名称
*/
function hanoiStackArray(plates, sourceName, helperName, destName) {
let source = new Stack()
let helper = new Stack()
let dest = new Stack()
for (let i = plates; i > 0; i--) {
source.push(i)
}
num = 0
return moveOfHanoi(
plates,
source,
helper,
dest,
sourceName,
helperName,
destName
)
}
[完]
Javascript数据结构与算法--栈的实现与用法的更多相关文章
- javascript数据结构与算法---栈
javascript数据结构与算法---栈 在上一遍博客介绍了下列表,列表是最简单的一种结构,但是如果要处理一些比较复杂的结构,列表显得太简陋了,所以我们需要某种和列表类似但是更复杂的数据结构---栈 ...
- JavaScript数据结构与算法-栈练习
栈的实现 // 栈类 function Stack () { this.dataStore = []; this.top = 0; // 栈顶位置 相当于length,不是索引. this.push ...
- JavaScript数据结构和算法----栈
前言 栈是一种遵循后进先出(LIFO)原则的有序集合,新添加的或待删除的元素都保存在栈的末尾,称作栈顶,另外一端就叫栈底.在栈里,新元素都靠近栈顶,旧元素都接近栈底.可以想象桌上的一叠书,或者厨房里的 ...
- javascript数据结构与算法——栈
前言: 栈就是和列表类似的一种数据结构,不过栈的特点是'后人先出'.栈是一种高效的数据结构,因为数据只能在栈顶添加或删除,所以这样操作很快,而且容易实现. 1. 栈的介绍: 栈是一种特殊的列表,栈内的 ...
- 为什么我要放弃javaScript数据结构与算法(第三章)—— 栈
有两种结构类似于数组,但在添加和删除元素时更加可控,它们就是栈和队列. 第三章 栈 栈数据结构 栈是一种遵循后进先出(LIFO)原则的有序集合.新添加的或待删除的元素都保存在栈的同一端,称为栈顶,另一 ...
- 重读《学习JavaScript数据结构与算法-第三版》- 第4章 栈
定场诗 金山竹影几千秋,云索高飞水自流: 万里长江飘玉带,一轮银月滚金球. 远自湖北三千里,近到江南十六州: 美景一时观不透,天缘有分画中游. 前言 本章是重读<学习JavaScript数据结构 ...
- JavaScript 数据结构与算法之美 - 线性表(数组、栈、队列、链表)
前言 基础知识就像是一座大楼的地基,它决定了我们的技术高度. 我们应该多掌握一些可移值的技术或者再过十几年应该都不会过时的技术,数据结构与算法就是其中之一. 栈.队列.链表.堆 是数据结构与算法中的基 ...
- JavaScript 数据结构与算法之美 - 栈内存与堆内存 、浅拷贝与深拷贝
前言 想写好前端,先练好内功. 栈内存与堆内存 .浅拷贝与深拷贝,可以说是前端程序员的内功,要知其然,知其所以然. 笔者写的 JavaScript 数据结构与算法之美 系列用的语言是 JavaScri ...
- javascript数据结构与算法---队列
javascript数据结构与算法---队列 队列是一种列表,不同的是队列只能在队尾插入元素,在队首删除元素.队列用于存储按顺序排列的数据,先进先出,这点和栈不一样(后入先出).在栈中,最后入栈的元素 ...
随机推荐
- MySQL物理备份 lvm-snapshot
MySQL备份之 lvm-snapshot lvm-snapshot(工具备份) 优点: 几乎是热备(穿件快照前把表上锁,创建完成后立即释放) 支持所有引擎 备份速度快 无需使用昂贵的商业软件(它是操 ...
- 3-ftp搭建成功,服务器能访问,外网无法连接和访问
登录 ECS 管理控制台,找到相应的实例. 在实例的右侧单击管理,进入实例详情页面.选择本实例安全组. 在安全组列表页面,找到相应的安全组,单击配置规则. 在安全组规则页面,单击添加安全组规则. 在添 ...
- python 私有方法
最近了解到python私有方法的来由: Python中默认的成员函数,成员变量都是公开的(public),而且python中没有类似public,private等关键词来修饰成员函数,成员变量. 在p ...
- 网络&协议目录
HTTP [基础] HTTP入门学习 网络基础 数据传输 网站架构演化 连接管理 缓存 [组成] URL 报文起始行 报文首部 [结构] Web服务器 代理 网关.隧道和中继 [安全] Web攻击技术 ...
- neufz
~~~~1--1--5--2020/4/23 08:50:30|1--1--5--2020/4/23 08:50:30|1--1--5--2020/4/23 08:50:30|1--1--5--202 ...
- python 使用win32com实现对word文档批量替换页眉页脚
最近由于工作需要,需要将70个word文件的页眉页脚全部进行修改,在想到这个无聊/重复/没有任何技术含量的工作时,我的内心是相当奔溃的.就在我接近奔溃的时候我突然想到完全可以用python脚本来实现这 ...
- 在没联网环境下,启动tomcat出错
使用SSH框架,在联网情况下,项目可以正常运行,当一旦断网,则启动服务器报错: org.hibernate.HibernateException: Could not parse configurat ...
- webpack配置less
webpack4.0把webpack.config.js隐藏起来了,需要先暴露出来,在webpack修改配置
- mysql:The user specified as a definer ('xxx'@'%') does not exist 解决方法
发生这种问题.大概率是用户不存在或者是权限不够 用户不存在.用可视化工具新建一个. 权限不够 ,运行下面命令: 如:我的错误: The user specified as a definer ('mo ...
- pyenv安装及常用命令
1.pyenv安装 #下载安装脚本curl https://pyenv.run | bash #添加环境变量 echo 'export PATH="/root/.pyenv/bin:$PAT ...