forked from trekhleb/javascript-algorithms
-
Notifications
You must be signed in to change notification settings - Fork 3
/
prim.js
73 lines (60 loc) · 2.5 KB
/
prim.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import Graph from '../../../data-structures/graph/Graph';
import PriorityQueue from '../../../data-structures/priority-queue/PriorityQueue';
/**
* @param {Graph} graph
* @return {Graph}
*/
export default function prim(graph) {
// It should fire error if graph is directed since the algorithm works only
// for undirected graphs.
if (graph.isDirected) {
throw new Error('Prim\'s algorithms works only for undirected graphs');
}
// Init new graph that will contain minimum spanning tree of original graph.
const minimumSpanningTree = new Graph();
// This priority queue will contain all the edges that are starting from
// visited nodes and they will be ranked by edge weight - so that on each step
// we would always pick the edge with minimal edge weight.
const edgesQueue = new PriorityQueue();
// Set of vertices that has been already visited.
const visitedVertices = {};
// Vertex from which we will start graph traversal.
const startVertex = graph.getAllVertices()[0];
// Add start vertex to the set of visited ones.
visitedVertices[startVertex.getKey()] = startVertex;
// Add all edges of start vertex to the queue.
startVertex.getEdges().forEach((graphEdge) => {
edgesQueue.add(graphEdge, graphEdge.weight);
});
// Now let's explore all queued edges.
while (!edgesQueue.isEmpty()) {
// Fetch next queued edge with minimal weight.
/** @var {GraphEdge} currentEdge */
const currentMinEdge = edgesQueue.poll();
// Find out the next unvisited minimal vertex to traverse.
let nextMinVertex = null;
if (!visitedVertices[currentMinEdge.startVertex.getKey()]) {
nextMinVertex = currentMinEdge.startVertex;
} else if (!visitedVertices[currentMinEdge.endVertex.getKey()]) {
nextMinVertex = currentMinEdge.endVertex;
}
// If all vertices of current edge has been already visited then skip this round.
if (nextMinVertex) {
// Add current min edge to MST.
minimumSpanningTree.addEdge(currentMinEdge);
// Add vertex to the set of visited ones.
visitedVertices[nextMinVertex.getKey()] = nextMinVertex;
// Add all current vertex's edges to the queue.
nextMinVertex.getEdges().forEach((graphEdge) => {
// Add only vertices that link to unvisited nodes.
if (
!visitedVertices[graphEdge.startVertex.getKey()]
|| !visitedVertices[graphEdge.endVertex.getKey()]
) {
edgesQueue.add(graphEdge, graphEdge.weight);
}
});
}
}
return minimumSpanningTree;
}