第四章:javascript: 栈
列表是一种最自然的数据组织方式。上一章已经介绍如何使用List类将数据组织成一个列表。如果数据存储的顺序不重要。也不必对数据进行查找,那么列表就是一种再好不过的数据结构。对于其它的一些应用,列表就显得有些简陋了。我们需要某种和列表类似但更复杂的数据结构。
栈就是和列表类似的一种数据结构,它可以用来解决计算机世界里很多的问题。栈是一种高效的数据结构,因为数据只能在栈顶添加或删除,所以这样的操作很快,而且容易实现。栈的使用遍布程序语言的方方面面,从表达式求值到处理函数调用。
一:对栈的操作
栈是一种特殊列表,栈内的元素只能通过列表的一端访问,这一端被称为栈顶。咖啡厅的一摞盘子是现实世界中最常见的栈的例子。只能从上面取盘子,盘子洗净后,也只能摞在这一摞盘子的最上面。栈被称为一种后入先出(LIFO,last-in-first-out)的数据结构。
由于栈具有后入先出的特点,所有任何不在栈顶的元素都无法访问,为了拿到栈底的元素,必选先拿掉上面的元素。如图:
对于栈的两种主要操作是将一个元素压入栈和将一个元素弹出栈,入栈使用push()方法。出栈使用pop()方法。
另外一个常用操作是预览栈顶的元素。pop()方法虽然可以访问栈顶的元素,但是调用该方法后,栈顶的元素也从栈中永久的删除了。peek()方法则只返回栈顶元素,而不删除它。
为了记录栈顶元素的位置,同时也为了标记哪里可以增加新的元素。我们使用变量top,当向栈内压入元素时,该变量增大,从栈内弹出元素时,该变量减小。
push(),pop()和peek()是栈的三个主要操作方法,但是栈还有其他的方法和属性。clear()方法清除栈内所有元素,length属性记录栈内元素的个数。我们还定义了一个empty属性,用于表示栈内是否还有元素(使用length也可以达到同样的目的)。
二:栈的实现:
实现一个栈,当务之急是决定存储数据的底层数据结构。这里采用的是数组。
我们实现以Stack类的构造函数开始:
function Stack() {
this.dataStore = [];
this.top = 0;
this.push = push;
this.pop = pop;
this.peek = peek;
}
我们使用数组dataStore保存栈内元素,构造函数将其初始化为一个空数组,变量top记录栈顶的位置,被构造的函数初始化为0,表示栈顶对于数组的起始位置为0.如果有元素压入栈,该变量的值随之变化。
先来实现push()方法。当向栈内压入一个新元素时,需要将其保存在数组中top所对应的位置,然后将top加1.让其指向数组中的下一个空位置。
function push (element) {
this.dataStore[this.top++] = element;
}
这里特别要注意++操作符的位置,它放在this.top的后面,这样新入栈的元素就被放在top的当前值对应的位置,然后再将top值加1.指向下一个位置。
pop()方法恰好与push()方法相反,它返回栈顶元素,同时将变量top的值减1.
function pop() {
return this.dataStore[--this.top]
}
peek()方法返回数组的第top-1个位置的元素,即栈顶元素:
function peek() {
return this.dataStore[this.top - 1]
}
如果对空数组调用peek()方法,结果为undefined。这是因为栈是空的,栈顶没有任何元素。
有时候需要知道栈内存储了多个元素。length()方法通过返回变量top值返回栈内元素的个数;
function length() {
return this.top
}
最后,可以将top的值设置为0,轻松清空一个栈。
function clear() {
this.top = 0;
}
附:测试代码
function Stack() {
this.dataStore = [];
this.top = 0;
this.push = push;
this.pop = pop;
this.peek = peek;
this.clear = clear;
this.length = length;
} //压入栈
function push (element) {
this.dataStore[this.top++] = element;
} //弹出栈
function pop() {
return this.dataStore[--this.top]
} //栈顶元素
function peek() {
// if (this.dataStore[this.top - 1] == undefined) {
// return "none"
// }
return this.dataStore[this.top - 1]
} //清空栈
function clear() {
this.top = 0;
} //栈元素个数
function length() {
return this.top
} var newstak = new Stack();
newstak.push("牛牛")
newstak.push("豆豆")
newstak.push("花花") console.log(newstak.length())
console.log(newstak.peek()) var poped = newstak.pop();
console.log(poped);//
console.log(newstak.peek());//
newstak.clear(); console.log(newstak.length())
console.log(newstak.peek());
newstak.push("羊羊");
console.log(newstak);
console.log(newstak.peek());
三.使用Stack类
有一些问题特别适合用栈来解决,先介绍几个例子:
1.数制间互相转换
可以利用栈将一个数字从一种数值转换成另一种数制。假设想将数字n转换为以b为基数的数字。实现转换算法如下:
- 1.最高位为 n % b ,将此位压入栈
- 2.使用n / b 代替n
- 3.重复步骤1和2,直到n等于0,且没有余数。
- 4.持续将栈内元素弹出,直到栈为空。依次将这些元素排列,就得到转换后数字的字符串形式。
- (此算法只征对基数为2-9的情况)
使用栈,在javascript中实现该算法就很容易,下面就是该函数的定义,可以将数字转化为二至九进制的数字。
function mulBase(num, base) {
var s = new Stack();
do {
s.push(num % base);
num = Math.floor(num /= base);
} while (num > 0);
var converted = "";
while(s.length() > 0) {
converted += s.pop()
}
return converted;
}
下面展示了如果使用该方法将数字转换为二进制和八进制数。
将数字转换为二进制和八进制。
function mulBase(num, base) {
var s = new Stack();
do {
s.push(num % base);
num = Math.floor(num /= base);
} while (num > 0);
var converted = "";
while(s.length() > 0) {
converted += s.pop()
}
return converted;
} var num = 32;
var base = 2; var newNum = mulBase(num, base);
//32 converted to base 2 is 100000
console.log(num + " converted to base " + base + " is " + newNum) num = 125;
base = 8; var newNum = mulBase(num, base); //125 converted to base 8 is 175
console.log(num + " converted to base " + base + " is " + newNum)
2.回文。
回文是这样一种现象:一个单词,短语或数字,从前往后写和往后写都是一样的。比如: 单词"dad","racecar"就是回文。如果忽略空格和标点符号,下面的句子也是回文。“A man, a plan, a canal:Panama”; 数字1001也是回文。
使用栈,可以轻松判断一个字符串是否回文。我们将拿到的自字符串的每个字符按照从左至右的顺序压入栈。当字符串的字符都入栈后,栈内就保存了一个反转的字符串,最后的字符串在栈顶,第一个字符串在栈底。
字符串完整压入栈内后,通过持续弹出栈中的每个字母就可以得到一个新字符串,该字符串刚好与原来的字符串顺序相反。我们只需比较两个字符串即可。如果他们相等,就是一个回文。
例子:判断给定字符串是否回文。
function isPalindrome(word) {
var s = new Stack();
for (var i = 0; i < word.length; ++i) {
s.push(word[i]);
}
var word = "";
while(s.length() > 0) {
rword += s.pop();
}
if (word == rword) {
return true;
}
else {
return false;
}
} var word = "hello";
if (isPalindrome(word)) {
console.log(word + " 是回文的");
} else {
console.log(word + " 不是回文的")
} var word = "racecar";
if (isPalindrome(word)) {
console.log(word + " 是回文的");
} else {
console.log(word + " 不是回文的")
}
三:递归演示;
栈常用来实现编程语言,使用栈实现递归即为一例(这里只用栈来模拟递归过程)。
为了演示如何用栈实现递归,考虑以下求阶乘的递归定义。首先看看5的阶乘是如何定义的
5! = 5*4*3*2*1 = 120
下面是一个递归函数,可以计算任何数字的阶乘
function factorial(n) {
if (n === 0) {
return 1;
} else {
return n * factorial(n - 1)
}
}
使用栈来模拟计算5的阶乘,返回120
使用栈来模拟计算5!的过程,首先将数字从5到1压入栈,然后使用一个循环,将数字弹出连乘,就得到了5 的阶乘
function fact(n) {
var s = new Stack();
while (n > 1) {
s.push(n--);
} var product = 1;
while(s.length() > 0) {
product *= s.pop()
} return product;
}
(本章完结)
上一章:第三章:javascript: 列表 下一章:第五章: 队列
第四章:javascript: 栈的更多相关文章
- 第四章 JavaScript操作DOM对象
第四章 JavaScript操作DOM对象 一.DOM操作 DOM是Document Object Model的缩写,即文档对象模型,是基于文档编程的一套API接口,1988年,W3C发布了第一级 ...
- JavaScript DOM编程艺术第四章 — JavaScript图片库案例研究
这一章通过JavaScript图片库案例,学习了一些DOM属性. HTML代码 <!DOCTYPE html> <html> <head> <meta cha ...
- JQuery制作网页—— 第四章JavaScript对象及初识面向对象
1.对象:在JavaScript中,所有事物都是对象,如字符串.数值.数组.函数等. JavaScript中的基本数据类型: number(数值类型) string(字符串类型) boolean ...
- 第四章 javascript的语句、对象笔记摘要
表达式语句 greeting ="Hello"+name;//赋值语句 i*=3; count++; delete o.x; //删除 alert(greeting); //函数 ...
- 第四章 JavaScript对象及初始面向对象
创建对象: //方式一 var ower=new Object(); ower.name="长春花"; ower.genera="夹竹挑科 长春花属"; owe ...
- 为什么我要放弃javaScript数据结构与算法(第四章)—— 队列
有两种结构类似于数组,但在添加和删除元素时更加可控,它们就是栈和队列. 第四章 队列 队列数据结构 队列是遵循FIFO(First In First Out,先进先出,也称为先来先服务)原则的一组有序 ...
- [书籍翻译] 《JavaScript并发编程》第四章 使用Generators实现惰性计算
本文是我翻译<JavaScript Concurrency>书籍的第四章 使用Generators实现惰性计算,该书主要以Promises.Generator.Web workers等技术 ...
- 读《编写可维护的JavaScript》第四章总结
第四章 变量 函数和运算符 4.1 ① 变量声明 变量声明是通过var语句来完成的,并且所有的var语句都提前到包含这段逻辑的函数的顶部执行. function doSomething() { + v ...
- Javascript权威指南——第二章词法结构,第三章类型、值和变量,第四章表达式和运算符,第五章语句
第二章 词法结构 一.HTML并不区分大小写(尽管XHTML区分大小写),而javascript区分大小写:在HTML中,这些标签和属性名可以使用大写也可以使用小写,而在javascript中必须小写 ...
- JavaScript高级程序设计:第十四章
第十四章 一.表单的基础知识 在HTML中,表单是由<form>元素来表示的,而在javascript中,表单对应的则是HTMLFormElement类型.HTMLFormElement继 ...
随机推荐
- Linux主流發行版本介紹
一.简介 而工欲善其事,必先利其器,Linux的世界相當廣大,除了最著名的Ubuntu以外還有不少發行版.然文人相輕,自古皆然,了解不同發行版的優勢不只嘴上攻防用的上,也是學Linux一個有趣的地方! ...
- visual studio 2013 快捷键大全
1.回到上一个光标位置/前进到下一个光标位置 1)回到上一个光标位置:使用组合键“Ctrl + -”: 2)前进到下一个光标位置:“Ctrl + Shift + - ”. 2.复制/剪切/删除整行代码 ...
- beeline vs hive cli
近期,大数据开发环境升级为cloudera 5.3. 配套的hive版本升级为0.13.1.可以使用心仪已久的分析开窗函数了.但在使用的过程中发现一些问题,仅记于此. 1.在使用hive命令的时候,发 ...
- WEB安全--Google Hacking
通常我们用Google查询一些我们测试站点的一些信息,Google提供了一系列的搜索语句,下面我为大家详细的介绍一下! 常用语法: site:指定域名 intext:正文中存在关键字的网页 intit ...
- 【读书笔记《Android游戏编程之从零开始》】15.游戏开发基础(剪切区域)
剪切区域也称为可视区域,是由画布进行设置的:它指的是在画布上设置一块区域,当画布一旦设置了可视区域,那么除此区域外,绘制的任何内容都将看不到:可视区域可以是圆形.矩形等等. 画布提供了三种设置可视区域 ...
- 【Javascript Demo】JS获取当前对象大小以及屏幕分辨率等
效果如下: 代码如下: <html> <head> <title>获取当前对象大小以及屏幕分辨率等</title> <body> <d ...
- C# 使用NLog记录日志
NLog是一个记录日志组件,和log4net一样被广泛使用,它可以将日志保存到文本文件.CSV.控制台.VS调试窗口.数据库等.最近刚用到这个组件,觉得不错,水一篇. 下载 通过Nuget安装NLog ...
- swfobject.js视频播放插件
在网页中经常会用到视频播放的功能,下面介绍一下swfobject.js的视频播放应用:html代码结构: <div id="video_content"></di ...
- Web前端研发工程师编程能力飞升之路
今天看到这篇文章.写的非常有意思,于是转载了.看看我们都处于什么的阶段. [背景] 如果你是刚进入web前端研发领域,想试试这潭水有多深,看这篇文章吧:如果你是做了两三年web产品前端研发,迷茫找不着 ...
- 基础KMP两道
1. HDU 1711 Number Sequence 代码: #include <iostream> #include <cstdio> #include <cstri ...