详解堆的javascript实现方法


Posted in Javascript onNovember 29, 2016

堆的定义

最大(最小)堆是一棵每一个节点的键值都不小于(大于)其孩子(如果存在)的键值的树。大顶堆是一棵完全二叉树,同时也是一棵最大树。小顶堆是一棵完全完全二叉树,同时也是一棵最小树。

另外,记住这两个概念,对写代码太重要了:

      1、父节点和子节点的关系:看定义

      2、完全二叉树:参考[2]

基本操作

      1、Build(构建堆)

      2、Insert(插入)

      3、Delete(删除:最小或者最大的那个)

代码实现

首先,写代码前有两个非常重要的点:

      1、用一个数组就可以作为堆的存储结构,非常简单而且易操作;

      2、另外同样因为是数组作为存储结构,所以父子节点之间的关系就能根据索引就轻松找到对方了。

对于JavaScript以0作为数组索引开始,关系如下:

nLeftIndex = 2 * (nFatherIndex+1) - 1;
nRightIndex = 2* (nFatherIndex+1);

前面提到注意两个概念,是有助于理解的:

       1、因为是数组,所以父子节点的关系就不需要特殊的结构去维护了,索引之间通过计算就可以得到,省掉了很多麻烦。如果是链表结构,就会复杂很多;

       2、完全二叉树的概念可以参考[2],要求叶子节点从左往右填满,才能开始填充下一层,这就保证了不需要对数组整体进行大片的移动。这也是随机存储结构(数组)的短板:删除一个元素之后,整体往前移是比较费时的。这个特性也导致堆在删除元素的时候,要把最后一个叶子节点补充到树根节点的缘由

代码实现:

/******************************************************
* file : 堆
* author : "page"
* time : "2016/11/02"
*******************************************************/
function Heap()
{
 this.data = [];
}

Heap.prototype.print = function () {
 console.log("Heap: " + this.data);
}

Heap.prototype.build = function(data){
 // 初始化
 this.data = [];
 if (!data instanceof Array)
 return false;

 // 入堆
 for (var i = 0; i < data.length; ++i) {
 this.insert(data[i]);
 }

 return true;
}

Heap.prototype.insert = function( nValue ){
 if (!this.data instanceof Array) {
 this.data = [];
 }

 this.data.push(nValue);
 // 更新新节点
 var nIndex = this.data.length-1;
 var nFatherIndex = Math.floor((nIndex-1)/2);
 while (nFatherIndex > 0){
 if (this.data[nIndex] < this.data[nFatherIndex]) {
 var temp = this.data[nIndex];
 this.data[nIndex] = this.data[nFatherIndex];
 this.data[nFatherIndex] = temp;
 }

 nIndex = nFatherIndex;
 nFatherIndex = Math.floor((nIndex-1)/2);
 }
}

Heap.prototype.delete = function( ){
 if (!this.data instanceof Array) {
 return null;
 }

 var nIndex = 0;
 var nValue = this.data[nIndex];
 var nMaxIndex = this.data.length-1;
 // 更新新节点
 var nLeaf = this.data.pop();
 this.data[nIndex] = nLeaf;

 while (nIndex < nMaxIndex ){
 var nLeftIndex = 2 * (nIndex+1) - 1;
 var nRightIndex = 2 * (nIndex+1);

 // 找最小的一个子节点(nLeftIndex < nRightIndex)
 var nSelectIndex = nLeftIndex;
 if (nRightIndex < nMaxIndex) {
 nSelectIndex = (this.data[nLeftIndex] > this.data[nRightIndex]) ? nRightIndex : nLeftIndex;
 }

 if (nSelectIndex < nMaxIndex && this.data[nIndex] > this.data[nSelectIndex] ){
 var temp = this.data[nIndex];
 this.data[nIndex] = this.data[nSelectIndex];
 this.data[nSelectIndex] = temp;
 }

 nIndex = nSelectIndex;
 }

 return nValue;
}
// test
var heap = new Heap();
heap.build([1, 3, 5, 11, 4, 6, 7, 12, 15, 10, 9, 8]);
heap.print();
// insert
heap.insert(2);
heap.print();
// delete
heap.delete();
heap.print();

关于JavaScript的几点小结

这里是采用面向对象的一种实现方法,感觉上不是太优雅,不知道还有没有更好的表示方法和写法;

学习了数组的几个用法:push和pop的操作太好用了;

判断数组的方式也是临时从网上搜的(instanceof),印象不深刻,不用的话下次估计还是有可能忘掉。

参考

[1]《数据结构和算法分析:C语言描述》

[2]图解数据结构(8)——二叉堆

[3]>数据结构:堆

总结

JavaScript的数组实现了push和pop这些操作,许多其他语言也提供了类似的数据结构和操作(比如C++的Vector),同时也支持随机操作。所以,我开始想如果这些结构上简单的加上自动排序的概念,那么一个堆就轻松搞定了,后面看到C++ STL的make_heap就知道自己知道的太少了,但也庆幸自己思维方式是对的。JavaScript的没有去查,我想有或者实现起来很容易;
自己去实现了之后,发现这个结构也很简单,只要你肯去跟它亲密接触一次就可以了;

JavaScript的细节部分还是不太了解,比如数组的应用上还要再翻资料才能用;对于JavaScript的灵魂还是没有接触到,精髓部分需要不断的学习和练习;

这些代码,只要你去了解了概念,了解了编程的基础,就可以写的出来。但是,代码还可以写的更简洁,比如delete函数求最小的子节点的时候,左右节点的索引就不需要比较,肯定是左边的小。代码部分感觉还是可以继续优化和精简的。

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
javascript实现动态侧边栏代码
Feb 19 Javascript
禁用Tab键JS代码兼容Firefox和IE
Apr 18 Javascript
js中回调函数的学习笔记
Jul 31 Javascript
js 动态生成json对象、时时更新json对象的方法
Dec 02 Javascript
AngularJS框架的ng-app指令与自动加载实现方法分析
Jan 04 Javascript
原生javascript移动端滑动banner效果
Mar 10 Javascript
js中的事件委托或是事件代理使用详解
Jun 23 Javascript
vue-cli之router基本使用方法详解
Oct 17 Javascript
angularjs实现猜大小功能
Oct 23 Javascript
Angular动态绑定样式及改变UI框架样式的方法小结
Sep 03 Javascript
Angular6 用户自定义标签开发的实现方法
Jan 08 Javascript
Vue移动端项目实现使用手机预览调试操作
Jul 18 Javascript
Bootstrap Table使用心得总结
Nov 29 #Javascript
jQuery将表单序列化成一个Object对象的实例
Nov 29 #Javascript
利用CSS、JavaScript及Ajax实现图片预加载的方法
Nov 29 #Javascript
jQuery序列化表单成对象的简单实现
Nov 29 #Javascript
JS判断输入的字符串是否是数字的方法(正则表达式)
Nov 29 #Javascript
JS访问DOM节点方法详解
Nov 29 #Javascript
基于Node.js + WebSocket打造即时聊天程序嗨聊
Nov 29 #Javascript
You might like
基于mysql的论坛(1)
2006/10/09 PHP
ThinkPHP5实现作业管理系统中处理学生未交作业与已交作业信息的方法
2016/11/12 PHP
Laravel 中创建 Zip 压缩文件并提供下载的实现方法
2019/04/02 PHP
用jquery实现学校的校历(asp.net+jquery ui 1.72)
2010/01/01 Javascript
优化javascript的执行速度
2010/01/23 Javascript
网页前台通过js非法字符过滤代码(骂人的话等等)
2010/05/26 Javascript
JavaScript 程序编码规范
2010/11/23 Javascript
在Ajax中使用Flash实现跨域数据读取的实现方法
2010/12/02 Javascript
基于javascipt-dom编程 table对象的使用
2013/04/22 Javascript
js 图片随机不定向浮动的实现代码
2013/07/02 Javascript
jQuery - css() 方法示例详解
2014/01/16 Javascript
关闭浏览器窗口弹出提示框并且可以控制其失效
2014/04/15 Javascript
node.js中的fs.chmodSync方法使用说明
2014/12/18 Javascript
学习JavaScript设计模式(封装)
2015/11/26 Javascript
浅析Bootstrap表格的使用
2016/06/23 Javascript
jQuery简单实现iframe的高度根据页面内容自适应的方法
2016/08/01 Javascript
js date 格式化
2017/02/15 Javascript
javascript如何用递归写一个简单的树形结构示例
2017/09/06 Javascript
PHP实现基于Redis的MessageQueue队列封装操作示例
2019/02/02 Javascript
Python中使用 Selenium 实现网页截图实例
2014/07/18 Python
Python使用multiprocessing创建进程的方法
2015/06/04 Python
Python中逗号的三种作用实例分析
2015/06/08 Python
python正则表达式去除两个特殊字符间的内容方法
2018/12/24 Python
django中SMTP发送邮件配置详解
2019/07/19 Python
浅谈Python中的模块
2020/06/10 Python
python通过函数名调用函数的几种场景
2020/09/23 Python
matplotlib 范围选区(SpanSelector)的使用
2021/02/24 Python
详解使用HTML5 Canvas创建动态粒子网格动画
2016/12/14 HTML / CSS
Cult Gaia官网:美国生活方式品牌
2019/08/16 全球购物
2014年财务经理工作总结
2014/12/08 职场文书
谢师宴答谢词
2015/01/05 职场文书
南湾猴岛导游词
2015/02/09 职场文书
2016廉洁从业学习心得体会
2016/01/19 职场文书
2016年119消防宣传日活动总结
2016/04/05 职场文书
Python中with上下文管理协议的作用及用法
2022/03/18 Python
nginx七层负载均衡配置详解
2022/07/15 Servers