/* jshint strict: false */ // ////////////////////////////////////////////////////////////////////////////// // / @brief binary min heap // / // / @file // / // / DISCLAIMER // / // / Copyright 2011-2013 triagens GmbH, Cologne, Germany // / // / Licensed under the Apache License, Version 2.0 (the "License") // / you may not use this file except in compliance with the License. // / You may obtain a copy of the License at // / // / http://www.apache.org/licenses/LICENSE-2.0 // / // / Unless required by applicable law or agreed to in writing, software // / distributed under the License is distributed on an "AS IS" BASIS, // / WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // / See the License for the specific language governing permissions and // / limitations under the License. // / // / Copyright holder is triAGENS GmbH, Cologne, Germany // / // / @author Jan Steemann // / @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany // ////////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////////// // / This file contains significant portions from the min heap published here: // / http://github.com/bgrins/javascript-astar // / Copyright (c) 2010, Brian Grinstead, http://briangrinstead.com // / Freely distributable under the MIT License. // / Includes Binary Heap (with modifications) from Marijn Haverbeke. // / http://eloquentjavascript.net/appendix2.html // ////////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////////// // / @brief constructor // ////////////////////////////////////////////////////////////////////////////// function BinaryHeap (scoreFunction) { this.values = []; this.scoreFunction = scoreFunction; } BinaryHeap.prototype = { // ////////////////////////////////////////////////////////////////////////////// // / @brief push an element into the heap // ////////////////////////////////////////////////////////////////////////////// push: function (element) { this.values.push(element); this._sinkDown(this.values.length - 1); }, // ////////////////////////////////////////////////////////////////////////////// // / @brief pop the min element from the heap // ////////////////////////////////////////////////////////////////////////////// pop: function () { var result = this.values[0]; var end = this.values.pop(); if (this.values.length > 0) { this.values[0] = end; this._bubbleUp(0); } return result; }, // ////////////////////////////////////////////////////////////////////////////// // / @brief remove a specific element from the heap // ////////////////////////////////////////////////////////////////////////////// remove: function (node) { var i = this.values.indexOf(node); var end = this.values.pop(); if (i !== this.values.length - 1) { this.values[i] = end; if (this.scoreFunction(end) < this.scoreFunction(node)) { this._sinkDown(i); } else { this._bubbleUp(i); } } }, // ////////////////////////////////////////////////////////////////////////////// // / @brief return number of elements in heap // ////////////////////////////////////////////////////////////////////////////// size: function () { return this.values.length; }, // ////////////////////////////////////////////////////////////////////////////// // / @brief reposition an element in the heap // ////////////////////////////////////////////////////////////////////////////// rescoreElement: function (node) { this._sinkDown(this.values.indexOf(node)); }, // ////////////////////////////////////////////////////////////////////////////// // / @brief move an element down the heap // ////////////////////////////////////////////////////////////////////////////// _sinkDown: function (n) { var element = this.values[n]; while (n > 0) { var parentN = Math.floor((n + 1) / 2) - 1, parent = this.values[parentN]; if (this.scoreFunction(element) < this.scoreFunction(parent)) { this.values[parentN] = element; this.values[n] = parent; n = parentN; } else { break; } } }, // ////////////////////////////////////////////////////////////////////////////// // / @brief bubble up an element // ////////////////////////////////////////////////////////////////////////////// _bubbleUp: function (n) { var length = this.values.length, element = this.values[n], elemScore = this.scoreFunction(element); while (true) { var child2n = (n + 1) * 2; var child1n = child2n - 1; var swap = null; var child1Score; if (child1n < length) { var child1 = this.values[child1n]; child1Score = this.scoreFunction(child1); if (child1Score < elemScore) { swap = child1n; } } if (child2n < length) { var child2 = this.values[child2n]; var child2Score = this.scoreFunction(child2); if (child2Score < (swap === null ? elemScore : child1Score)) { swap = child2n; } } if (swap !== null) { this.values[n] = this.values[swap]; this.values[swap] = element; n = swap; } else { break; } } } }; exports.BinaryHeap = BinaryHeap;