Created
March 4, 2012 16:28
-
-
Save paullewis/1973769 to your computer and use it in GitHub Desktop.
Heap in JavaScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Can be tested with the following: | |
* | |
* var heap = new AEROTWIST.Heap(); | |
* | |
* for(var i = 10; i > 0; i--) { | |
* heap.add(Math.round(Math.random() * 100)); | |
* } | |
* | |
* for(var i = 10; i > 0; i--) { | |
* console.log(heap.remove()); | |
* } | |
*/ | |
/** Namespace */ | |
var AEROTWIST = AEROTWIST || {}; | |
/** | |
* @class Simple max-heap for priority queues and so on. | |
* | |
* @author Paul Lewis | |
*/ | |
AEROTWIST.Heap = function() { | |
this.items = []; | |
}; | |
AEROTWIST.Heap.prototype = { | |
/** | |
* Provides the index of the parent | |
* | |
* @param {int} index The start position | |
*/ | |
parentIndex: function(index) { | |
return Math.floor(index * 0.5); | |
}, | |
/** | |
* Provides the index of the left child | |
* | |
* @param {int} index The start position | |
*/ | |
leftChildIndex: function(index) { | |
return index * 2; | |
}, | |
/** | |
* Provides the index of the left child | |
* | |
* @param {int} index The start position | |
*/ | |
rightChildIndex: function(index) { | |
return (index * 2) + 1; | |
}, | |
/** | |
* Gets the value from a specific position | |
* in the heap | |
* | |
* @param {int} index The position | |
*/ | |
get: function(index) { | |
var value = null; | |
if(index >= 1) { | |
value = this.items[index - 1]; | |
} | |
return value; | |
}, | |
/** | |
* Sets a value in the heap | |
* | |
* @param {int} index The position in the heap | |
* @param {Float} value The value to set | |
*/ | |
set: function(index, value) { | |
this.items[index - 1] = value; | |
}, | |
/** | |
* Swaps two values in the heap | |
* | |
* @param {int} indexA Index of the first item to be swapped | |
* @param {int} indexB Index of the second item to be swapped | |
*/ | |
swap: function(indexA, indexB) { | |
var temp = this.get(indexA); | |
this.set(indexA, this.get(indexB)); | |
this.set(indexB, temp); | |
}, | |
/** | |
* Sends a value up heap. The item is compared | |
* to its parent item. If its value is greater | |
* then it's swapped and the process is repeated | |
* | |
* @param {int} startIndex The start position for the operation | |
*/ | |
upHeap: function(startIndex) { | |
var startValue = null, | |
parentValue = null, | |
parentIndex = null, | |
switched = false; | |
do { | |
switched = false; | |
parentIndex = this.parentIndex(startIndex); | |
startValue = this.get(startIndex); | |
parentValue = this.get(parentIndex); | |
switched = parentValue !== null && startValue >= parentValue; | |
if(switched) { | |
this.swap(startIndex, parentIndex); | |
startIndex = parentIndex; | |
} | |
} while(switched); | |
}, | |
/** | |
* Sends a value down heap. The item is compared | |
* to its two children item. If its value is less | |
* then it's swapped with the <em>highest value child</em> | |
* and the process is repeated | |
* | |
* @param {int} startIndex The start position for the operation | |
*/ | |
downHeap: function(startIndex) { | |
var startValue = null, | |
leftChildValue = null, | |
rightChildValue = null, | |
leftChildIndex = null, | |
rightChildIndex = null, | |
switchValue = null, | |
switched = false; | |
do { | |
switched = false; | |
leftChildIndex = this.leftChildIndex(startIndex); | |
rightChildIndex = this.rightChildIndex(startIndex); | |
startValue = this.get(startIndex); | |
leftChildValue = this.get(leftChildIndex) || Number.NEGATIVE_INFINITY; | |
rightChildValue = this.get(rightChildIndex) || Number.NEGATIVE_INFINITY; | |
switchValue = Math.max(leftChildValue, rightChildValue); | |
if(startValue < switchValue) { | |
if(rightChildValue === switchValue) { | |
this.swap(startIndex, rightChildIndex); | |
startIndex = rightChildIndex; | |
} else { | |
this.swap(startIndex, leftChildIndex); | |
startIndex = leftChildIndex; | |
} | |
switched = true; | |
} | |
} while(switched); | |
}, | |
/** | |
* Adds a value to the heap. For now this is just | |
* numbers but a comparator function could be used | |
* for more complex comparisons. | |
* | |
* @param {Float} value The value to be added to the heap | |
*/ | |
add: function(value) { | |
this.items.push(value); | |
this.upHeap(this.items.length); | |
}, | |
/** | |
* Removes the head of the heap | |
*/ | |
remove: function() { | |
var value = null; | |
// swap with the last child | |
// in the heap | |
this.swap(1, this.items.length); | |
// grab the value and truncate | |
// the item array | |
value = this.get(this.items.length); | |
this.items.length -= 1; | |
// push the swapped item | |
// down the heap to wherever it needs | |
// to sit | |
this.downHeap(1); | |
return value; | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment