详解堆的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动态调整iframe高度的代码
Apr 10 Javascript
图片Slider 带左右按钮的js示例
Aug 30 Javascript
动态的创建一个元素createElement及删除一个元素
Jan 24 Javascript
javascript嵌套函数和在函数内调用外部函数的区别分析
Jan 31 Javascript
老生常谈原生JS执行环境与作用域
Nov 22 Javascript
使用Promise链式调用解决多个异步回调的问题
Jan 15 Javascript
bootstrap折叠调用collapse()后data-parent不生效的快速解决办法
Feb 23 Javascript
Vue加载组件、动态加载组件的几种方式
Aug 31 Javascript
详解JavaScript 的变量
Mar 08 Javascript
详解如何提升JSON.stringify()的性能
Jun 12 Javascript
vue中keep-alive、activated的探讨和使用详解
Jul 26 Javascript
JQuery绑定事件四种实现方法解析
Dec 02 jQuery
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
Yii学习总结之安装配置
2015/02/22 PHP
php模拟服务器实现autoindex效果的方法
2015/03/10 PHP
php项目开发中用到的快速排序算法分析
2016/06/25 PHP
PHP批量获取网页中所有固定种子链接的方法
2016/11/18 PHP
js对象数组按属性快速排序
2011/01/31 Javascript
使用jspdf生成pdf报表
2015/07/03 Javascript
HTML5实现留言和回复页面样式
2015/07/22 Javascript
Bootstrap按钮功能之查询按钮和重置按钮
2016/10/26 Javascript
bootstrap daterangepicker汉化以及扩展功能
2017/06/15 Javascript
详解angularjs实现echart图表效果最简洁教程
2017/11/29 Javascript
微信小程序实现pdf、word等格式文件上传的方法
2019/09/10 Javascript
原生JS与CSS实现软件卸载对话框功能
2019/12/05 Javascript
使用Taro实现小程序商城的购物车功能模块的实例代码
2020/06/05 Javascript
js+h5 canvas实现图片验证码
2020/10/11 Javascript
vue+Element-ui实现分页效果
2020/11/15 Javascript
使用Typescript开发微信小程序的步骤详解
2021/01/12 Javascript
如何封装Vue Element的table表格组件
2021/02/06 Vue.js
[02:35]DOTA2超级联赛专访XB 难忘一年九冠称王
2013/06/20 DOTA
[01:12:27]EG vs Secret 2018国际邀请赛淘汰赛BO3 第二场 8.22
2018/08/23 DOTA
Python中的进程分支fork和exec详解
2015/04/11 Python
python框架中flask知识点总结
2018/08/17 Python
django开发post接口简单案例,获取参数值的方法
2018/12/11 Python
利用Python正则表达式过滤敏感词的方法
2019/01/21 Python
Pycharm远程调试原理及具体配置详解
2019/08/08 Python
Python依赖包迁移到断网环境操作
2020/07/13 Python
详解pyqt5的UI中嵌入matplotlib图形并实时刷新(挖坑和填坑)
2020/08/07 Python
实例讲解CSS3中Transform的perspective属性的用法
2016/04/22 HTML / CSS
解析html5 canvas实现背景鼠标连线动态效果代码
2019/06/17 HTML / CSS
.NET初级开发工程师面试题(包括Javascript)
2012/08/22 面试题
如何防止同一个帐户被多人同时登录
2013/08/01 面试题
2014年语文教师工作总结
2014/12/18 职场文书
一年级小学生评语大全
2014/12/25 职场文书
辞职信如何写
2015/02/27 职场文书
小学生勤俭节约倡议书
2015/04/29 职场文书
《孙子兵法》:欲成大事者,需读懂这些致胜策略
2019/08/23 职场文书
500字作文之难忘的同学
2019/12/20 职场文书