UNPKG

jkstra

Version:

Small JavaScript graph routing library

912 lines (751 loc) 32.7 kB
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.jkstra = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _constants = require('../core/constants.js'); function BFS(graph, opts) { var options = _extends({ flagKey: '_bfs' }, opts); var flagKey = options.flagKey; function clearFlags() { graph.forEachVertex(function (v) { delete v[flagKey]; }); } function mark(v) { v[flagKey] = true; } function isMarked(v) { return v[flagKey] === true; } var defaultTraversalOptions = { direction: _constants.OUT, onVisit: function onVisit(u) {}, onTestEdge: function onTestEdge(e) {}, edgeFilter: null // take all edges }; return { /** Traverse the graph using the breadth first algorithm, starting from source, with the specified options */ traverse: function traverse(source, opts) { var options = _extends({}, defaultTraversalOptions, opts); clearFlags(); var queue = []; queue.push(source); mark(source, null); var u = void 0, v = void 0, edges = void 0; while (queue.length > 0) { u = queue.shift(); options.onVisit(u); edges = graph.incidentEdges(u, options.direction, options.edgeFilter); edges.forEach(function (e) { options.onTestEdge(e); v = options.direction ? e.to : e.from; if (!isMarked(v)) { mark(v); queue.push(v); } }); } } }; } exports.default = BFS; module.exports = exports['default']; },{"../core/constants.js":7}],2:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _DijkstraIterator = require('../algos/DijkstraIterator.js'); var _DijkstraIterator2 = _interopRequireDefault(_DijkstraIterator); var _nodeFlagger = require('./nodeFlagger.js'); var _nodeFlagger2 = _interopRequireDefault(_nodeFlagger); var _constants = require('../core/constants.js'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var BidirectionalDijkstra = function () { function BidirectionalDijkstra(graph, opts) { _classCallCheck(this, BidirectionalDijkstra); this.graph = graph; this.options = _extends({}, opts); this.outKey = '_dijkstra_out'; this.inKey = '_dijkstra_in'; } _createClass(BidirectionalDijkstra, [{ key: 'rebuildPath', value: function rebuildPath(meetingNode) { var edges = []; var edge = void 0; var currentNode = meetingNode; // going upward in the tree until the first vertex (with no incoming edge) while ((edge = this.outFlagger.getFlags(currentNode).inc) !== null) { edges.push(edge); currentNode = edge.from; } edges.reverse(); currentNode = meetingNode; // going upward in the tree until the first vertex (with no incoming edge) while ((edge = this.inFlagger.getFlags(currentNode).inc) !== null) { edges.push(edge); currentNode = edge.to; } return edges; } }, { key: '_hasBeenReachBothWays', value: function _hasBeenReachBothWays(node) { var outState = this.outFlagger.getFlags(node); var inState = this.inFlagger.getFlags(node); return (outState.state === _constants.REACHED || outState.state === _constants.SETTLED) && (inState.state === _constants.REACHED || inState.state === _constants.SETTLED); } }, { key: 'shortestPath', value: function shortestPath(source, target, options) { var outIteraror = new _DijkstraIterator2.default(this.graph, source, _extends({}, options, options.OUT, { direction: _constants.OUT, flagKey: this.outKey })); var inIterator = new _DijkstraIterator2.default(this.graph, target, _extends({}, options, options.IN, { direction: _constants.IN, flagKey: this.inKey })); this.outFlagger = new _nodeFlagger2.default(this.graph, this.outKey); this.inFlagger = new _nodeFlagger2.default(this.graph, this.inKey); var iterator = outIteraror; var meetingNode = void 0; var next = void 0; // simply loop over the iterator until it ends while (!(next = iterator.next()).done) { if (this._hasBeenReachBothWays(next.value)) { meetingNode = next.value; break; } // alternate between the two iterators iterator = iterator === outIteraror ? inIterator : outIteraror; } if (meetingNode) { return this.rebuildPath(meetingNode); } return null; } }]); return BidirectionalDijkstra; }(); ; exports.default = BidirectionalDijkstra; module.exports = exports['default']; },{"../algos/DijkstraIterator.js":4,"../core/constants.js":7,"./nodeFlagger.js":5}],3:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _DijkstraIterator = require('../algos/DijkstraIterator.js'); var _DijkstraIterator2 = _interopRequireDefault(_DijkstraIterator); var _nodeFlagger = require('./nodeFlagger.js'); var _nodeFlagger2 = _interopRequireDefault(_nodeFlagger); var _constants = require('../core/constants.js'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Dijkstra = function () { function Dijkstra(graph, opts) { _classCallCheck(this, Dijkstra); this.graph = graph; this.options = _extends({ flagKey: '_dijkstra' }, opts); this.nodeFlagger = new _nodeFlagger2.default(this.graph, this.options.flagKey); } _createClass(Dijkstra, [{ key: 'rebuildPath', value: function rebuildPath(end) { var edges = []; var edge = void 0; // going upward in the tree until the first vertex (with no incoming edge) while ((edge = this.nodeFlagger.getFlags(end).inc) !== null) { edges.push(edge); end = edge.from; } return edges.reverse(); } }, { key: 'shortestPath', /** The most common use of Dijkstra traversal */ value: function shortestPath(source, target, opts) { var _this = this; var options = opts || {}; options.isFinished = function () { return _this.nodeFlagger.getFlags(target).state === _constants.SETTLED; }; var found = this.traverse(source, options); if (found) { return this.rebuildPath(target); } return null; } /** Traverse the graph using Dijkstra's algorithm, starting from source, with the specified options */ }, { key: 'traverse', value: function traverse(source, opts) { var options = _extends({}, Dijkstra.defaultTraversalOptions, opts); var dijkstraIterator = new _DijkstraIterator2.default(this.graph, source, opts); // simply loop over the iterator until it ends while (!dijkstraIterator.next().done && !options.isFinished()) {} // if false, means the whole graph was traversed return options.isFinished(); } }]); return Dijkstra; }(); Dijkstra.defaultTraversalOptions = { isFinished: function isFinished() { return false; } }; ; exports.default = Dijkstra; module.exports = exports['default']; },{"../algos/DijkstraIterator.js":4,"../core/constants.js":7,"./nodeFlagger.js":5}],4:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _updatablePriorityQueue = require('updatable-priority-queue'); var _updatablePriorityQueue2 = _interopRequireDefault(_updatablePriorityQueue); var _nodeFlagger = require('./nodeFlagger.js'); var _nodeFlagger2 = _interopRequireDefault(_nodeFlagger); var _constants = require('../core/constants.js'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var DijkstraIterator = function () { function DijkstraIterator(graph, source, opts) { _classCallCheck(this, DijkstraIterator); this.graph = graph; this.source = source; this.options = _extends({}, DijkstraIterator.defaultOptions, opts); this.flags = new _nodeFlagger2.default(this.graph, this.options.flagKey); this.pQ = new _updatablePriorityQueue2.default(); this._initTraversal(); } _createClass(DijkstraIterator, [{ key: '_reach', value: function _reach(v, incEdge, fCost, gCost, action) { // update state to "reached", and register cost and incomingEdge this.flags.setFlags(v, { state: _constants.REACHED, fCost: fCost, gCost: gCost, inc: incEdge }); if (action) { action(v); } } }, { key: '_settle', value: function _settle(v, action) { this.flags.setFlags(v, { state: _constants.SETTLED }); if (action) { action(v); } } }, { key: '_initTraversal', value: function _initTraversal() { // reset node tagging this.flags.clearFlags(this.graph); this.pQ.insert(this.source, this.options.heuristic(this.source)); this._reach(this.source, null, this.options.heuristic(this.source), 0, this.options.onReach); } }, { key: 'next', value: function next() { // if no more node available in the queue, // return the iterator end signal if (this.pQ.count === 0) { return { done: true }; } var _options = this.options, direction = _options.direction, onReach = _options.onReach, onSettle = _options.onSettle, edgeFilter = _options.edgeFilter, edgeCost = _options.edgeCost, heuristic = _options.heuristic, shouldUpdateKey = _options.shouldUpdateKey; var u = this.pQ.pop().item; var v = void 0; var vFlags = void 0; var uGCost = this.flags.getFlags(u).gCost; var vFCost = void 0, vGCost = void 0; this._settle(u, onSettle); var edges = this.graph.incidentEdges(u, direction, edgeFilter); var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = edges[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var e = _step.value; v = direction === _constants.OUT ? e.to : e.from; vFlags = this.flags.getFlags(v); if (vFlags.state !== _constants.SETTLED) { vGCost = uGCost + edgeCost(e, uGCost); vFCost = vGCost + heuristic(v); if (vFlags.state !== _constants.REACHED) { this.pQ.insert(v, vFCost); this._reach(v, e, vFCost, vGCost, onReach); } else { if (shouldUpdateKey(vFlags.fCost, vFCost, vFlags.inc, e)) { this.pQ.updateKey(v, vFCost); this._reach(v, e, vFCost, vGCost, onReach); } } } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return { value: u }; } }]); return DijkstraIterator; }(); DijkstraIterator.defaultOptions = { flagKey: '_dijkstra', direction: _constants.OUT, shouldUpdateKey: function shouldUpdateKey(prevCost, newCost) { return newCost < prevCost; }, edgeCost: function edgeCost(e, costDone) { return 1; }, heuristic: function heuristic(v) { return 0; }, onReach: null, // nothing special to do when reaching a node onSettle: null, // nothing special to do when setting a node edgeFilter: null // take all edges }; ; exports.default = DijkstraIterator; module.exports = exports['default']; },{"../core/constants.js":7,"./nodeFlagger.js":5,"updatable-priority-queue":10}],5:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var _class = function () { function _class(graph, flagKey) { _classCallCheck(this, _class); this.graph = graph; this.flagKey = flagKey; } _createClass(_class, [{ key: "clearFlags", value: function clearFlags(graph) { var _this = this; this.graph.forEachVertex(function (v) { delete v[_this.flagKey]; }); } }, { key: "getFlags", value: function getFlags(v) { return v[this.flagKey] || {}; } }, { key: "setFlags", value: function setFlags(v, flags) { if (!v.hasOwnProperty(this.flagKey)) { v[this.flagKey] = {}; } for (var key in flags) { v[this.flagKey][key] = flags[key]; } } }]); return _class; }(); exports.default = _class; module.exports = exports['default']; },{}],6:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _constants = require('./constants.js'); var _utils = require('./utils.js'); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Graph = function () { function Graph() { _classCallCheck(this, Graph); this.vertices = []; this.edges = []; } _createClass(Graph, [{ key: 'addVertex', value: function addVertex(data) { var vertex = { _in: [], _out: [], data: data }; this.vertices.push(vertex); return vertex; } }, { key: 'addEdge', value: function addEdge(from, to, data) { var edge = { from: from, to: to, data: data || {} }; from._out.push(edge); to._in.push(edge); this.edges.push(edge); return edge; } /** Shortcut to add an edge and its reverse, sharing the same data. */ }, { key: 'addEdgePair', value: function addEdgePair(a, b, data) { return [this.addEdge(a, b, data), this.addEdge(b, a, data)]; } }, { key: 'removeEdge', value: function removeEdge(edge) { var index = this.edges.indexOf(edge); if (index !== -1) { // remove from extremity this.vertices first edge.from._out.splice(edge.from._out.indexOf(edge), 1); edge.to._in.splice(edge.to._in.indexOf(edge), 1); this.edges.splice(index, 1); } } }, { key: 'removeVertex', value: function removeVertex(vertex) { var index = this.vertices.indexOf(vertex); if (index !== -1) { // remove all incident this.edges first var edgesToRemove = vertex._in.concat(vertex._out); for (var i = 0; i < edgesToRemove.length; i++) { this.removeEdge(edgesToRemove[i]); } this.vertices.splice(index, 1); } } }, { key: 'outEdges', value: function outEdges(vertex, filter) { return this.incidentEdges(vertex, _constants.OUT, filter); } }, { key: 'inEdges', value: function inEdges(vertex, filter) { return this.incidentEdges(vertex, _constants.IN, filter); } /** Returns all this.edges incident to a vertex, in one direction (outgoing or incoming), optionnaly filtered by a given function. */ }, { key: 'incidentEdges', value: function incidentEdges(vertex, direction, filter) { if (!filter) { return direction ? vertex._out : vertex._in; } var edges = direction ? vertex._out : vertex._in; return edges.filter(filter); } }, { key: 'vertex', value: function vertex(props) { var vertices = this.vertices; for (var i = 0, l = vertices.length; i < l; i++) { if ((0, _utils.propsMatch)(vertices[i].data, props)) { return vertices[i]; } } return null; } }, { key: 'edge', value: function edge(props) { var edges = this.edges; for (var i = 0, l = edges.length; i < l; i++) { if ((0, _utils.propsMatch)(edges[i].data, props)) { return edges[i]; } } return null; } /** Perform an action on each vertex of the graph */ }, { key: 'forEachVertex', value: function forEachVertex(action) { this.vertices.forEach(function (v) { return action(v); }); } /** Perform an action on each edge of the graph */ }, { key: 'forEachEdge', value: function forEachEdge(action) { this.edges.forEach(function (e) { return action(e); }); } }, { key: 'vertexCount', get: function get() { return this.vertices.length; } }, { key: 'edgeCount', get: function get() { return this.edges.length; } }]); return Graph; }(); ; exports.default = Graph; module.exports = exports['default']; },{"./constants.js":7,"./utils.js":8}],7:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var OUT = exports.OUT = true; var IN = exports.IN = false; var REACHED = exports.REACHED = 1; var SETTLED = exports.SETTLED = 2; },{}],8:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; exports.propsMatch = propsMatch; function isScalar(o) { return (/boolean|number|string/.test(typeof o === "undefined" ? "undefined" : _typeof(o)) ); }; function propsMatch(set, subSet) { if (subSet === null) { return set === null; } if (isScalar(set)) { return isScalar(subSet) && set === subSet; } for (var p in subSet) { if (set.hasOwnProperty(p)) { if (!propsMatch(set[p], subSet[p])) { return false; } } else { return false; } } return true; }; },{}],9:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _BFS = require("./algos/BFS.js"); var _BFS2 = _interopRequireDefault(_BFS); var _DijkstraIterator = require("./algos/DijkstraIterator.js"); var _DijkstraIterator2 = _interopRequireDefault(_DijkstraIterator); var _Dijkstra = require("./algos/Dijkstra.js"); var _Dijkstra2 = _interopRequireDefault(_Dijkstra); var _BidirectionalDijkstra = require("./algos/BidirectionalDijkstra.js"); var _BidirectionalDijkstra2 = _interopRequireDefault(_BidirectionalDijkstra); var _Graph = require("./core/Graph.js"); var _Graph2 = _interopRequireDefault(_Graph); var _constants = require("./core/constants.js"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var jkstra = { IN: _constants.IN, OUT: _constants.OUT, Graph: _Graph2.default, algos: { BFS: _BFS2.default, Dijkstra: _Dijkstra2.default, BidirectionalDijkstra: _BidirectionalDijkstra2.default, DijkstraIterator: _DijkstraIterator2.default } }; exports.default = jkstra; module.exports = exports['default']; },{"./algos/BFS.js":1,"./algos/BidirectionalDijkstra.js":2,"./algos/Dijkstra.js":3,"./algos/DijkstraIterator.js":4,"./core/Graph.js":6,"./core/constants.js":7}],10:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var PriorityQueue = function () { function PriorityQueue() { _classCallCheck(this, PriorityQueue); this.heap = []; } // TODO: make it an option, for max or min priority queue _createClass(PriorityQueue, [{ key: "_compare", value: function _compare(a, b) { return a.key - b.key; } }, { key: "_bubbleUp", value: function _bubbleUp(idx) { var element = this.heap[idx]; var parentIdx = void 0; var parent = void 0; while (idx > 0) { // Compute the parent element's index, and fetch it. parentIdx = Math.floor((idx + 1) / 2) - 1; parent = this.heap[parentIdx]; // If the parent has a lesser score, things are in order and we // are done. if (this._compare(element, parent) > 0) { break; } // Otherwise, swap the parent with the current element and // continue. this.heap[parentIdx] = element; this.heap[idx] = parent; idx = parentIdx; } } }, { key: "_sinkDown", value: function _sinkDown(idx) { var length = this.heap.length; var element = this.heap[idx]; var swapIdx = void 0; while (true) { var rChildIdx = (idx + 1) * 2; var lChildIdx = rChildIdx - 1; swapIdx = -1; // if the first child exists if (lChildIdx < length) { var lChild = this.heap[lChildIdx]; // and is lower than the element, they must be swapped if (this._compare(lChild, element) < 0) { swapIdx = lChildIdx; } // unless there is another lesser child, which will be the one swapped if (rChildIdx < length) { var rChild = this.heap[rChildIdx]; if ((swapIdx === -1 || this._compare(rChild, lChild) < 0) && this._compare(rChild, element) < 0) { swapIdx = rChildIdx; } } } // if no swap occurs, the element found its right place if (swapIdx === -1) { break; } // otherwise, swap and continue on next tree level this.heap[idx] = this.heap[swapIdx]; this.heap[swapIdx] = element; idx = swapIdx; } } }, { key: "_findElementIndex", value: function _findElementIndex(item) { // TODO: optimize for (var i = 0, l = this.heap.length; i < l; i++) { if (this.heap[i].item === item) { return i; } } return -1; } }, { key: "insert", value: function insert(item, key) { this.heap.push({ item: item, key: key }); this._bubbleUp(this.heap.length - 1); } }, { key: "pop", value: function pop() { if (this.heap.length === 0) { return null; } var element = this.heap[0]; var end = this.heap.pop(); // replace the first element by the last, // and let it sink to its right place if (this.heap.length > 0) { this.heap[0] = end; this._sinkDown(0); } return element; } }, { key: "peek", value: function peek() { if (this.heap.length === 0) { return null; } return this.heap[0]; } }, { key: "updateKey", value: function updateKey(item, newKey) { var idx = this._findElementIndex(item); if (idx === -1) { return; } var oldKey = this.heap[idx].key; this.heap[idx].key = newKey; if (newKey < oldKey) { this._bubbleUp(idx); } else { this._sinkDown(idx); } } }, { key: "count", get: function get() { return this.heap.length; } }]); return PriorityQueue; }(); ; exports.default = PriorityQueue; module.exports = exports['default']; },{}]},{},[9])(9) });