1
\$\begingroup\$

I wrote this heap implementation because I need it to run Dijkstra's algorithm to find paths in a game (for which reason I'd like this implementation not to be unreasonably slow...)

Sadly I don't know JavaScript well, much worse than C or C++ for sure, so I might've made some silly mistakes, I'd love You to point them out for me :)

For example, I'm unsure if keeping heap nodes in an array is an OK approach here; sadly I can't find the relevant SO post now, but I remember reading on SO that using arrays as memory pools results in a gross performance degradation in JavaScript. Keeping nodes in an array is pretty convinient for implementing a heap, but should I have refrained from this anyway?

Also I am aware that people usually tell me my coding style is horrible and unreadable, so I suppose I'm going to get similar comments here, how exactly did I fail this time?

The code seems correct though, it passes this test: https://paste.ee/p/edrYt which was generated with this C++ code: https://ideone.com/zpCtIz

Ah and I tried to stick to JSv5, I tried to refreain from using ES6 features. I hope none slipped through.

var GZKM = GZKM || {}
;(function() {
GZKM.Heap = function() {
 this.arr = []
}
GZKM.Heap.prototype._parentIndex = function(i) {
 return Math.floor((i+1)/2)-1
}
GZKM.Heap.prototype._leftChildIndex = function(i) {
 return 2*(i+1)-1
}
GZKM.Heap.prototype._rightChildIndex = function(i) {
 return 2*(i+1)
}
GZKM.Heap.prototype._swapNodes = function(node1, node2) {
 // Idea taken from this SO answer: https://stackoverflow.com/a/22053474/4385532
 // Doing it this way b/c this SO answer scared me that the standard way may lead to a memory leak: https://stackoverflow.com/a/872433/4385532
 this.arr[node1._i] = [this.arr[node2._i], this.arr[node2._i]=this.arr[node1._i]][0]
 node1._i = [node2._i, node2._i=node1._i][0]
}
GZKM.Heap.prototype._moveUp = function(node) {
 var canMove = function() {
 return node._i > 0
 }
 var mustMove = function() {
 return this.arr[this._parentIndex(node._i)].priority > node.priority
 }.bind(this)
 while(canMove() && mustMove())
 this._swapNodes(node, this.arr[this._parentIndex(node._i)])
}
GZKM.Heap.prototype._moveDown = function(node) {
 var canMove = function() {
 return this._leftChildIndex(node._i) < this.arr.length
 }.bind(this) 
 var nextNode = function() {
 if(this._rightChildIndex(node._i) >= this.arr.length ||
 this.arr[this._rightChildIndex(node._i)].priority > this.arr[this._leftChildIndex(node._i)].priority)
 return this.arr[this._leftChildIndex(node._i)]
 else return this.arr[this._rightChildIndex(node._i)]
 }.bind(this)
 var mustMove = function() {
 return nextNode().priority < node.priority
 }
 while(canMove() && mustMove())
 this._swapNodes(node, nextNode())
}
GZKM.Heap.prototype.push = function(priority, elt) {
 var eltIndex = this.arr.length;
 this.arr.push({elt: elt, priority: priority, _i: eltIndex})
 var ret = this.arr[eltIndex]
 this._moveUp(this.arr[eltIndex])
 return ret
}
GZKM.Heap.prototype.pop = function() {
 if(!this.arr.length) return undefined
 this._swapNodes(this.arr[0], this.arr[this.arr.length-1])
 var ret = this.arr.pop()
 this._moveDown(this.arr[0])
 return ret
}
GZKM.Heap.prototype.reprioritize = function(node, newPriority) {
 node.priority = newPriority
 this._moveUp(node)
 this._moveDown(node)
}
})()
asked Oct 4, 2017 at 9:46
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Big f...reakin' bug:

GZKM.Heap.prototype.pop = function() {
 if(!this.arr.length) return undefined
 this._swapNodes(this.arr[0], this.arr[this.arr.length-1])
 var ret = this.arr.pop()
 this._moveDown(this.arr[0])
 return ret
}

After this.arr.pop() the array may very well be empty, and _moveDown is not prepared to being called with undefined, so we will get an exception here. I really thought the tests would cover this...well, they didn't.

Fixing this seems simple though:

if(this.arr.length)
 this._moveDown(this.arr[0])
answered Oct 21, 2017 at 18:36
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.