详解堆的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 getComputedStyle获取和设置style的原理
Oct 10 Javascript
JS控件的生命周期介绍
Oct 22 Javascript
Jquery写一个鼠标拖动效果实现原理与代码
Dec 24 Javascript
《JavaScript高级编程》学习笔记之object和array引用类型
Nov 01 Javascript
Spring mvc 接收json对象
Dec 10 Javascript
Webpack 实现 AngularJS 的延迟加载
Mar 02 Javascript
Node.js环境下JavaScript实现单链表与双链表结构
Jun 12 Javascript
JavaScript初学者必看“new”
Jun 12 Javascript
详解Node.js 中使用 ECDSA 签名遇到的坑
Nov 26 Javascript
微信小程序实现日历功能
Nov 27 Javascript
vue data恢复初始化数据的实现方法
Oct 31 Javascript
京东优选小程序的实现代码示例
Feb 25 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
PHP模糊查询的实现方法(推荐)
2016/09/06 PHP
laravel添加前台跳转成功页面示例
2019/10/22 PHP
javascript 避免闭包引发的问题
2009/03/17 Javascript
JQuery Tips(2) 关于$()包装集你不知道的
2009/12/14 Javascript
json格式化/压缩工具 Chrome插件扩展版
2010/05/25 Javascript
jquery.blockUI.js上传滚动等待效果实现思路及代码
2013/03/18 Javascript
js调试系列 源码定位与调试[基础篇]
2014/06/18 Javascript
MVC+jQuery.Ajax异步实现增删改查和分页
2020/12/22 Javascript
关于JSON.parse(),JSON.stringify(),jQuery.parseJSON()的用法
2016/06/30 Javascript
jQuery实现鼠标跟随效果
2017/02/20 Javascript
JavaScript中Promise的使用详解
2017/02/26 Javascript
利用ES6语法重构React组件详解
2017/03/02 Javascript
解决Extjs下拉框不显示的问题
2017/06/21 Javascript
nodejs 搭建简易服务器的图文教程(推荐)
2017/07/18 NodeJs
解决vue同一slot在组件中渲染多次的问题
2018/09/06 Javascript
JS实现手风琴特效
2020/11/08 Javascript
[50:28]2018DOTA2亚洲邀请赛 3.31 小组赛 A组 Newbee vs KG
2018/04/01 DOTA
[58:54]EG vs RNG 2019国际邀请赛小组赛 BO2 第一场 8.16
2019/08/18 DOTA
pandas groupby 分组取每组的前几行记录方法
2018/04/20 Python
python获取指定字符串中重复模式最高的字符串方法
2018/06/29 Python
利用Pyhton中的requests包进行网页访问测试的方法
2018/12/26 Python
Tensorflow实现神经网络拟合线性回归
2019/07/19 Python
python 读取修改pcap包的例子
2019/07/23 Python
django数据关系一对多、多对多模型、自关联的建立
2019/07/24 Python
mac使用python识别图形验证码功能
2020/01/10 Python
python实现学生信息管理系统源码
2021/02/22 Python
集体婚礼策划方案
2014/02/22 职场文书
餐厅执行经理岗位职责范本
2014/02/26 职场文书
银行爱岗敬业演讲稿
2014/05/05 职场文书
幼儿园端午节活动方案
2014/08/25 职场文书
低碳环保演讲稿
2014/08/28 职场文书
住房抵押登记委托书
2014/09/27 职场文书
2014年基建工作总结
2014/12/12 职场文书
高一军训决心书
2015/02/05 职场文书
2016年学习雷锋精神广播稿
2015/12/17 职场文书
如何写好开幕词?
2019/06/24 职场文书