javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例
栈(Stack)是限定仅在表尾进行插入或删除操作的线性表。表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈。
栈又称为后进先出(last in first out)的线性表。
堆栈可以用链表和数组两种方式实现,一般为一个堆栈预先分配一个大小固定且较合适的空间并非难事,所以较流行的做法是 Stack
结构下含一个数组。如果空间实在紧张,也可用链表实现,且去掉表头。
栈的链式表示结构图:
用js数组可以非常简单地实现栈的顺序表示,故这里不赘述。这里主要讲解一下栈的链式表示。
// 找的链式表示
function Stack() {
this.top = null;
this.size = 0;
}
module.exports = Stack;
Stack.prototype = {
constructor: Stack,
push: function (data) {
var node = {
data: data,
next: null
}; node.next = this.top;
this.top = node;
this.size++;
},
peek: function () {
return this.top === null ?
null :
this.top.data;
},
pop: function () {
if (this.top === null) return null; var out = this.top;
this.top = this.top.next; if (this.size > 0) this.size--; return out.data;
},
clear: function () {
this.top = null;
this.size = 0;
},
displayAll: function () {
if (this.top === null) return null; var arr = [];
var current = this.top; for (var i = 0, len = this.size; i < len; i++) {
arr[i] = current.data;
current = current.next;
} return arr;
}
}; var stack = new Stack(); stack.push(1);
stack.push('asd'); stack.pop();
stack.push({a: 1});
console.log(stack);
相关单元测试:
describe('stack tests', function(){
var stack = new Stack(); it('should push into stack', function(){
stack.push(1);
expect(stack.peek()).toBe(1);
stack.push('asd');
expect(stack.peek()).toBe('asd');
expect(stack.size).toBe(2);
}); it('should pop from stack', function(){
stack.pop();
expect(stack.peek()).toBe(1);
expect(stack.size).toBe(1);
stack.push({a: 1});
expect(stack.peek()).toEqual({a: 1});
expect(stack.size).toBe(2);
}); it('should be an empty stack', function(){
stack.pop();
expect(stack.peek()).toBe(1);
stack.pop();
expect(stack.peek()).toBe(null);
expect(stack.size).toBe(0);
});
});
堆栈的应用
示例1:数值进制转换
公式: N = (N / d) * d + N % d
N:十进制数值, d:需要转换的进制数
function numTransform(number, rad) {
var s = new Stack(); while (number) {
s.push(number % rad);
number = parseInt(number / 8, 10);
} var arr = [];
while (s.top) {
arr.push(s.pop());
}
console.log(arr.join(''));
} numTransform(1348, 8);
numTransform(1348, 2);
示例2:括号匹配检查
在算法中设置一个栈,每读入一个括号,若是右括号,则或者使置于栈顶的最急迫的期待得以消解,或者是不合法的情况;若是左括号,则作为一个新的更急迫的期待压入栈中,自然使得原有的在栈中的所有未消解的期待的急迫性都降一级。另外,在算法开始和结束时,栈都应该是空的。
function bracketsMatch(str) {
var stack = new Stack();
var text = ''; for (var i = 0, len = str.length; i < len; i++) {
var c = str[i];
if (c === '[') {
stack.push(c);
} else if (c === ']') {
if (!stack.top || stack.pop() !== '[') throw new Error('unexpected brackets:' + c);
} else {
text += c;
}
}
console.log(text);
} console.log(bracketsMatch('[asd]')); function Matcher(left, right) {
this.left = left;
this.right = right;
this.stack = new Stack();
}
Matcher.prototype = {
match: function (str) {
var text = ''; for (var i = 0, len = str.length; i < len; i++) {
var c = str[i];
if (c === this.left) {
this.stack.push(c);
} else if (c === this.right) {
if (!this.stack.top || this.stack.pop() !== this.left) {
throw new Error('unexpected brackets:' + c);
} else {
text += ',';
}
} else {
text += c;
}
}
console.log(text);
return text;
}
};
var m = new Matcher('{', '}');
m.match('[{123}123');
示例3:行编辑
当用户发现刚刚键入的一个字符是错的时,可补进一个退格符“#”,以表示前一个字符无效;如果发现当前键入的行内差错较多或难以补进,则可以键入一个退行符“@”
,以表示当前行中的字符均无效。
为此,可设这个输入缓冲区为一个栈结构,每当从终端接收了一个字符之后先做如下判断:
如果它既不是"#"也不是"@",则将字符压入栈;
如果是"#",则从栈顶删去一个字符;
如果是"@",则清空栈。
function LineEditor(str) {
this.stack = new Stack();
this.str = str || ''
}
LineEditor.prototype = {
getResult: function () {
var stack = this.stack;
var str = this.str;
for (var i = 0, len = str.length; i < len; i++) {
var c = str[i];
switch (c) {
case '#':
stack.pop();
break;
case '@':
stack.clear();
break;
default:
stack.push(c);
break;
}
} var result = '';
var current = stack.top;
while (current) {
result = current.data + result;
current = current.next;
} return result;
}
}; var le = new LineEditor('whli##ilr#e(s#*s)\
\noutcha@putchar(*s=#++)');
console.log(le.getResult());
示例4:表达式求值
表达式求值是程序设计语言编译中的一个最基本问题、它的实现是栈应用的又一个典型例子。这里介绍一种简单直观,广为使用的算法,通常称为“运算符优先法”。
// from: http://wuzhiwei.net/ds_app_stack/ var prioty = {
"+": 1,
"-": 1,
"%": 2,
"*": 2,
"/": 2,
"^": 3,
"(": 0,
")": 0,
"`": -1
}; function doop(op, opn1, opn2) {
switch (op) {
case "+":
return opn1 + opn2;
case "-":
return opn1 - opn2;
case "*":
return opn1 * opn2;
case "/":
return opn1 / opn2;
case "%":
return opn1 % opn2;
case "^":
return Math.pow(opn1, opn2);
default:
return 0;
}
} function opcomp(a, b) {
return prioty[a] - prioty[b];
} function calInfixExpression(exp) {
var cs = [];
var ns = [];
exp = exp.replace(/\s/g, "");
exp += '`';
if (exp[0] === '-') {
exp = "0" + exp;
}
var c;
var op;
var opn1;
var opn2;
for (var i = 0; i < exp.length; ++i) {
c = exp[i];
// 如果是操作符
if (c in prioty) {
// 如果右边不是左括号且操作符栈的栈顶元素优先权比右边大
// 循环遍历进行连续运算
while (c != '(' && cs.length && opcomp(cs[cs.length - 1], c) >= 0) {
// 出栈的操作符
op = cs.pop();
// 如果不是左括号或者右括号,说明是运算符
if (op != '(' && op != ')') {
// 出栈保存数字的栈的两个元素
opn2 = ns.pop();
opn1 = ns.pop();
// 将与操作符运算后的结果保存到栈顶
ns.push(doop(op, opn1, opn2));
}
}
// 如果右边不是右括号,保存到操作符栈中
if (c != ')') cs.push(c);
} else {
// 多位数的数字的情况
while (!(exp[i] in prioty)) {
i++;
c += exp[i];
}
ns.push(parseFloat(c));
i--;
}
}
return ns.length ? ns[0] : NaN;
} var exp1 = calInfixExpression('5+3*4/2-2^3+5%2');
console.log(exp1);
栈与递归调用的实现:
栈的另一个重要应用是在程序设计语言中实现递归调用。
递归调用:一个函数(或过程)直接或间接地调用自己本身,简称递归(Recursive)。
递归是程序设计中的一个强有力的工具。因为递归函数结构清晰,程序易读,正确性很容易得到证明。
为了使递归调用不至于无终止地进行下去,实际上有效的递归调用函数(或过程)应包括两部分:递推规则(方法),终止条件。
为保证递归调用正确执行,系统设立一个“递归工作栈”,作为整个递归调用过程期间使用的数据存储区。
每一层递归包含的信息如:参数、局部变量、上一层的返回地址构成一个“工作记录” 。每进入一层递归,就产生一个新的工作记录压入栈顶;每退出一层递归,就从栈顶弹出一个工作记录。
从被调函数返回调用函数的一般步骤:
(1) 若栈为空,则执行正常返回。
⑵ 从栈顶弹出一个工作记录。
⑶ 将“工作记录”中的参数值、局部变量值赋给相应的变量;读取返回地址。
⑷ 将函数值赋给相应的变量。
(5) 转移到返回地址。
相关:
javascript实现数据结构与算法系列
javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例的更多相关文章
- javascript实现数据结构与算法系列
1.线性表(Linear list) 线性表--简单示例及线性表的顺序表示和实现 线性表--线性链表(链式存储结构) 线性表的静态单链表存储结构 循环链表与双向链表 功能完整的线性链表 线性链表的例子 ...
- javascript实现数据结构与算法系列:循环链表与双向链表
循环链表(circular linked list) 是另一种形式的链式存储结构.它的特点是表中最后一个结点的指针域指向头结点,整个表形成一个环. 循环链表的操作和线性链表基本一致,仅有细微差别. w ...
- javascript实现数据结构与算法系列:功能完整的线性链表
由于链表在空间的合理利用上和插入,删除时不需要移动等的有点,因此在很多场合下,它是线性表的首选存储结构.然而,它也存在着实现某些基本操作,如求线性表长度时不如顺序存储结构的缺点:另一方面,由于在链表中 ...
- javascript实现数据结构与算法系列:线性表的静态单链表存储结构
有时可借用一维数组来描述线性链表,这就是线性表的静态单链表存储结构. 在静态链表中,数组的一个分量表示一个结点,同时用游标(cur)代替指针指示结点在数组中的相对位置.数组的第0分量可看成头结点,其指 ...
- javascript实现数据结构与算法系列:队列 -- 链队列和循环队列实现及示例
1 队列的基本概念 队列(Queue):也是运算受限的线性表.是一种先进先出(First In First Out ,简称FIFO)的线性表.只允许在表的一端进行插入,而在另一端进行删除. 队首(fr ...
- JavaScript 版数据结构与算法(二)队列
今天,我们要讲的是数据结构与算法中的队列. 队列简介 队列是什么?队列是一种先进先出(FIFO)的数据结构.队列有什么用呢?队列通常用来描述算法或生活中的一些先进先出的场景,比如: 在图的广度优先遍历 ...
- 数据结构与算法系列2 线性表 链表的分类+使用java实现链表+链表源码详解
数据结构与算法系列2.2 线性表 什么是链表? 链表是一种物理存储单元上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表的链接次序实现的一系列节点组成,节点可以在运行时动态生成,每个节点包括两个 ...
- C#数据结构与算法系列(一):介绍
1.介绍 数据结构:是指相互之间存在一种或多种特定关系的数据元素的集合用计算机存储.组织数据的方式.数据结构分别为逻辑结构.(存储)物理结构和数据的运算三个部分. 数据结构包括:线性结构和非线性结构. ...
- 数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解
数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...
随机推荐
- 低功耗蓝牙(BLE)透传模块 ——RF-BM-S01(BQB认证)
本文来源深圳信驰达科技www.szrfstar.com,技术交流群336720020. 低功耗蓝牙(BLE)透传模块 ——RF-BM-S01(BQB认证) 深圳市信驰达科技有限公司 2013年3月18 ...
- programming ruby
ri #rdoc reader attr_reader attr_writer @@xx 类变量都是私有的 def 类名.xx end 类方法 [1,3,5,7].inject(0){|sum,e| ...
- cygwin
setup-x86_64 -q -P wget,tar,qawk,bzip2,subversion,vim wget rawgit.com/transcode-open/apt-cyg/master/ ...
- poj 2631 Roads in the North
题目连接 http://poj.org/problem?id=2631 Roads in the North Description Building and maintaining roads am ...
- android开发系列之MVP设计模式
最近在开发一个android的项目中,发现了一个很实用的设计模式(MVP).大家可能一看到这个名字就有点蒙,MVP到底是什么鬼呢?它的好用到底体现在哪呢?别着急,下面就让我们一一分享出来. 说到MVP ...
- SqlBulkCopy与触发器,批量插入表(存在则更新,不存在则插入)
临时表:Test /****** 对象: Table [dbo].[Test] 脚本日期: 05/10/2013 11:42:07 ******/ SET ANSI_NULLS ON GO SET Q ...
- MySQL 触发器简单实例
~~语法~~ CREATE TRIGGER <触发器名称> --触发器必须有名字,最多64个字符,可能后面会附有分隔符.它和MySQL中其他对象的命名方式基本相象.{ BEFORE | ...
- 三星N8000/N8010通用刷机教程
前面已经讲到过如何给三星n8000/n8010 Galaxy Note 10.1获取ROOT权限了.接下来就顺便告诉大家怎么给三星n8000/n8010刷机吧.其实给三星n8000/n8010刷机过程 ...
- 使用 Swift 制作一个新闻通知中心插件(2)
我们在第一部分的文章中详细讲解了创建一个通知中心插件的整体过程.我们成功的在通知中心里面显示了新闻列表.但是截止到目前,我们还不能从通知中心的列表中查看新闻的详细内容.在这次的教程中,我们就以上次的教 ...
- Django ajax MYSQL Highcharts<1>
Another small project with django/Ajax/Mysql/Highcharts. 看下效果图 - delivery dashboard .嘿嘿 是不是还蛮好看的. 废 ...