详解堆的javascript实现方法_javascript技巧

堆的定义

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

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

      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堆栈
javascript闭包详解、javascript详解、javascript 继承详解、javascript bind详解、javascript this 详解,以便于您获取更多的相关知识。

时间: 2024-11-01 13:58:48

详解堆的javascript实现方法_javascript技巧的相关文章

javascript事件冒泡详解和捕获、阻止方法_javascript技巧

一.事件的发生顺序 这个问题的起源非常简单,假设你在一个元素中又嵌套了另一个元素 复制代码 代码如下: ----------------------------------- | element1                        | |   -------------------------     | |   |element2               |     | |   -------------------------     | |                 

CascadeView级联组件实现思路详解(分离思想和单链表)_javascript技巧

本文介绍自己最近做省市级联的类似的级联功能的实现思路,为了尽可能地做到职责分离跟表现与行为分离,这个功能拆分成了2个组件并用到了单链表来实现关键的级联逻辑,下一段有演示效果的gif图.虽然这是个很常见的功能,但是本文的实现逻辑清晰,代码好理解,脱离了省市级联这样的语义,考虑了表现与行为的分离,希望本文的内容能够为你的工作带来一些参考的价值,欢迎阅读和指正. Cascade 级联操作 CascadeType. PERSIST 级联持久化 ( 保存 ) 操作 CascadeType. MERGE 级

详解Bootstrap各式各样的按钮(推荐)_javascript技巧

Bootstrap为我们提供了各式各样漂亮的按钮,我们无需自己给按钮写样式,直接使用它给我们提供的类样式,使用在我们的按钮上,非常的简单方便. 为尊重原创这里贴一下参考的教程:http://www.runoob.com/bootstrap/bootstrap-buttons.html.在我的很多笔记中,您可能会看到我贴的www.runoob.com相关的网址,在这里先声明这不是广告,我只是觉得每个人的劳动成果都应该被尊重.这个网站收集了很多的信息,供我学习,我非常的感激,借鉴于这些很好的教程,我

详解PHP序列化反序列化的方法_php技巧

经常看到一些配置文件里面存放的是一些类似带有格式的变量名称和值,其实就是一个序列化的过程,在需要用到这些数据库的时候会进行一个反序列化过程,就是将这个字符串再还原成他原来的数据结构.下面说说php 如何进行数据的序列化和反序列化的. php 将数据序列化和反序列化其实就用到两个函数,serialize 和unserialize.serialize 将数组格式化成有序的字符串unserialize 将数组还原成数组例如: $user=array('Moe','Larry','Curly'); $u

JS 在数组插入字符的实现代码(可参考JavaScript splice() 方法)_javascript技巧

复制代码 代码如下: Array.prototype.ArrayInsertAfter=function(Num,obj) { var tempArr=new Array(); var l=this.length; for(var i=0;i<l;i++) { tempArr.push(this.shift()); } l=tempArr.length; for(var i=0;i<l;i++) { this.push(tempArr.shift()); if(i==Num) { this.p

第七篇Bootstrap表单布局实例代码详解(三种表单布局)_javascript技巧

Bootstrap提供了三种表单布局:垂直表单,内联表单和水平表单.下面逐一给大家介绍,有兴趣的朋友一起学习吧. 创建垂直或基本表单: •·向父 <form> 元素添加 role="form". •·把标签和控件放在一个带有 class .form-group 的 <div> 中.这是获取最佳间距所必需的. •·向所有的文本元素 <input>.<textarea> 和 <select> 添加 class .form-cont

JavaScript Split()方法_javascript技巧

split()方法的定义和用法: split()方法可以利用字符串的子字符串的作为分隔符将字符串分割为字符串数组,并返回此数组. 注:作为分割符的子字符串不会成为返回的数组的元素的一部分或者数组元素的一员. 这里只介绍使用普通字符作为分隔符,关于使用正则表达式作为分隔符的可以参阅正则表达式split()函数一章节. 点击可参阅更多相关String对象方法和属性. 语法结构: 复制代码 代码如下: stringObject.split(separator,limit) 参数列表: 参数 描述 se

详解jquery uploadify 上传文件_javascript技巧

网上找了一天,大家都说Uploadify唯一的缺点就是不支持中文按钮,杯具之前,我看了下Uploadify的API,才发现了几个参数没被大家提及的,这正是解决此问题的关键.(以后坚决养成没事就看API的习惯)    Uploadify有一个参数是 buttonText 这个无论你怎么改都不支持中文,因为插件在js里用了一个转码方法把这个参数的值转过码了,解码的地方在那个swf文件里,看不到代码,所以这条路不行.    另一个参数,网上很少提到,是 buttonImg( 按钮图片),这时你完全可以

IE的有条件注释判定IE版本详解(附实例代码)_javascript技巧

IE的有条件注释是一种专有的(因此是非标准的).对常规(X)HTML注释的Miscrosoft扩展.顾名思义,有条件注释使你能够根据条件(比如浏览器版本)显示代码块.尽管是非标准的,但是有条件注释对于其他所有浏览器作为常规注释出现,因此本质上是无害的.有条件注释在Windows上的IE5中首次出现,并且得到了Widnows浏览器所有后续版本的支持. IE的有条件注释及其有效,而且非常容易记住.主要的缺点是这些注释需要放在HTML页面中,而不是放在CSS中.这样,当你不需要这些东西,或者有所更改的