Skip to content

Instantly share code, notes, and snippets.

@samteb
Created July 5, 2019 15:40
Show Gist options
  • Save samteb/93622ceef8f9a514e8cfa6cc4b828cf4 to your computer and use it in GitHub Desktop.
Save samteb/93622ceef8f9a514e8cfa6cc4b828cf4 to your computer and use it in GitHub Desktop.
class Node {
constructor (value, priority) {
this.value = value;
this.priority = priority;
}
}
class PriorityQueue {
constructor () {
this.values = [];
}
enqueue (value, priority) {
const node = new Node(value, priority);
this.values.push(node);
this.bubbleUp();
}
bubbleUp () {
let idx = this.values.length - 1;
const element = this.values[idx];
while (idx > 0) {
const parentIdx = Math.floor((idx - 1) / 2);
const parent = this.values[parentIdx];
if (parent.priority <= element.priority) break;
this.values[parentIdx] = element;
this.values[idx] = parent;
idx = parentIdx;
}
}
dequeue () {
const max = this.values[0];
const end = this.values.pop();
if (this.values.length > 0){
this.values[0] = end;
this.sinkDown();
}
return max;
}
sinkDown () {
let idx = 0;
const element = this.values[idx];
const length = this.values.length;
while (true) {
const leftChildIdx = 2 * idx + 1;
const rightChildIdx = 2 * idx + 2;
let leftChild = null;
let rightChild = null;
let swapIdx = null;
if (leftChildIdx < length) {
leftChild = this.values[leftChildIdx];
if (leftChild.priority < element.priority) {
swapIdx = leftChildIdx;
}
}
if (rightChildIdx < length) {
rightChild = this.values[rightChildIdx];
if (
(swapIdx === null && rightChild.priority < element.priority) ||
(swapIdx !== null && rightChild.priority < leftChild.priority)
) {
swapIdx = rightChildIdx;
}
}
if (swapIdx === null) break;
this.values[idx] = this.values[swapIdx];
this.values[swapIdx] = element;
idx = swapIdx;
}
}
}
class WeightedGraph {
constructor () {
this.adjacencyList = {};
}
addVertex (vertex) {
if (!this.adjacencyList[vertex]) {
this.adjacencyList[vertex] = [];
}
}
addEdge (vertex1, vertex2, weight) {
if (this.adjacencyList[vertex1] && this.adjacencyList[vertex2]) {
this.adjacencyList[vertex1].push({ node: vertex2, weight });
this.adjacencyList[vertex2].push({ node: vertex1, weight });
}
}
dijkstra (start, end) {
const queue = new PriorityQueue();
const distances = {};
const previous = {};
let path = [];
let length = 0;
let smallest;
for (const vertex in this.adjacencyList) {
previous[vertex] = null;
if (vertex === start) {
distances[vertex] = 0;
queue.enqueue(vertex, 0);
} else {
distances[vertex] = Infinity;
queue.enqueue(vertex, Infinity);
}
}
while (queue.values.length) {
smallest = queue.dequeue().value;
if (smallest === end) {
length = distances[smallest];
while (previous[smallest]) {
path.push(smallest);
smallest = previous[smallest];
}
path.push(start);
path = path.reverse();
break;
}
if (smallest || distances[smallest] !== Infinity) {
for (const neighbor of this.adjacencyList[smallest]) {
const neighborVertex = neighbor.node;
const neighborWeight = neighbor.weight;
const newDistance = distances[smallest] + neighborWeight;
if (newDistance < distances[neighborVertex]) {
distances[neighborVertex] = newDistance;
previous[neighborVertex] = smallest;
queue.enqueue(neighborVertex, newDistance);
}
}
}
}
return { path, length };
}
}
const graph = new WeightedGraph();
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addVertex('D');
graph.addVertex('E');
graph.addVertex('F');
graph.addEdge('A','B', 4);
graph.addEdge('A','C', 2);
graph.addEdge('B','E', 3);
graph.addEdge('C','D', 2);
graph.addEdge('C','F', 4);
graph.addEdge('D','E', 3);
graph.addEdge('D','F', 1);
graph.addEdge('E','F', 1);
graph.dijkstra('A', 'E');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment