详解堆的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数字和字符串转换示例
Mar 26 Javascript
JavaScript通过this变量快速找出用户选中radio按钮的方法
Mar 23 Javascript
包含中国城市的javascript对象实例
Aug 03 Javascript
BootStrap实现响应式布局导航栏折叠隐藏效果(在小屏幕、手机屏幕浏览时自动折叠隐藏)
Nov 30 Javascript
JavaScript基本类型值-Undefined、Null、Boolean
Feb 23 Javascript
详解Vue.js入门环境搭建
Mar 17 Javascript
jquery.rotate.js实现可选抽奖次数和中奖内容的转盘抽奖代码
Aug 23 jQuery
微信小程序之数据缓存的实例详解
Sep 29 Javascript
node.js基于fs模块对系统文件及目录进行读写操作的方法详解
Nov 10 Javascript
微信小程序实现动态改变view标签宽度和高度的方法【附demo源码下载】
Dec 05 Javascript
微信小程序switch开关选择器使用详解
Jan 31 Javascript
Vue 递归多级菜单的实例代码
May 05 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模块 Memcached功能多于Memcache
2011/06/14 PHP
PHP将Excel导入数据库及数据库数据导出至Excel的方法
2015/06/24 PHP
PHP微信分享开发详解
2017/01/14 PHP
PHP实现二叉树深度优先遍历(前序、中序、后序)和广度优先遍历(层次)实例详解
2018/04/20 PHP
CentOS7系统搭建LAMP及更新PHP版本操作详解
2020/03/26 PHP
转自Jquery官方 jQuery1.1.3发布,速度提升800%,体积保持20K
2007/08/19 Javascript
本地对象Array的原型扩展实现代码
2010/12/04 Javascript
基于JQuery的多标签实现代码
2012/09/19 Javascript
.net,js捕捉文本框回车键事件的小例子(兼容多浏览器)
2013/03/11 Javascript
在jquery中combobox多选的不兼容问题总结
2013/12/24 Javascript
JQuery的$命名冲突详细解析
2013/12/28 Javascript
纯Javascript实现ping功能的方法
2015/03/20 Javascript
js实现YouKu的漂亮搜索框效果
2015/08/19 Javascript
node.js require() 源码解读
2015/12/13 Javascript
浅析函数声明和函数表达式——函数声明的声明提前
2016/05/03 Javascript
详解JavaScript常量定义
2017/01/03 Javascript
JavaScript实现网页头部进度条刷新
2017/04/16 Javascript
Jquery-data的三种用法
2017/04/18 jQuery
vue element项目引入icon图标的方法
2018/06/06 Javascript
vue实现在一个方法执行完后执行另一个方法的示例
2018/08/25 Javascript
基于Angularjs-router动态改变Title值的问题
2018/08/30 Javascript
JS字符串与二进制的相互转化实例代码详解
2019/06/28 Javascript
JavaScript:ES2019 的新特性(译)
2019/08/08 Javascript
layer关闭当前窗口页面以及确认取消按钮的方法
2019/09/09 Javascript
vue在线动态切换主题色方案
2020/03/26 Javascript
使用JavaScript获取扫码枪扫描得到的条形码的思路代码详解
2020/06/10 Javascript
vue3.0实现点击切换验证码(组件)及校验
2020/11/18 Vue.js
Python3.x对JSON的一些操作示例
2017/09/01 Python
Python cv2 图像自适应灰度直方图均衡化处理方法
2018/12/07 Python
python调用matplotlib模块绘制柱状图
2019/10/18 Python
python通用读取vcf文件的类(复制粘贴即可用)
2020/02/29 Python
keras得到每层的系数方式
2020/06/15 Python
俄罗斯宠物用品网上商店:ZooMag
2019/12/12 全球购物
人力资源管理求职信
2014/08/07 职场文书
答谢词范文
2015/01/05 职场文书
JPA如何使用entityManager执行SQL并指定返回类型
2021/06/15 Java/Android