-
-
Notifications
You must be signed in to change notification settings - Fork 408
/
Copy pathprim.ts
72 lines (66 loc) · 2.32 KB
/
prim.ts
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
import { PriorityQueue } from '../data_structures/heap/heap'
/**
* @function prim
* @description Compute a minimum spanning tree(MST) of a fully connected weighted undirected graph. The input graph is in adjacency list form. It is a multidimensional array of edges. graph[i] holds the edges for the i'th node. Each edge is a 2-tuple where the 0'th item is the destination node, and the 1'th item is the edge weight.
* @Complexity_Analysis
* Time complexity: O(Elog(V))
* Space Complexity: O(V)
* @param {[number, number][][]} graph - The graph in adjacency list form
* @return {Edge[], number} - [The edges of the minimum spanning tree, the sum of the weights of the edges in the tree]
* @see https://en.wikipedia.org/wiki/Prim%27s_algorithm
*/
export const prim = (graph: [number, number][][]): [Edge[], number] => {
if (graph.length == 0) {
return [[], 0]
}
const minimum_spanning_tree: Edge[] = []
let total_weight = 0
const priorityQueue = new PriorityQueue(
(e: Edge) => {
return e.b
},
graph.length,
(a: Edge, b: Edge) => {
return a.weight < b.weight
}
)
const visited = new Set<number>()
// Start from the 0'th node. For fully connected graphs, we can start from any node and still produce the MST.
visited.add(0)
add_children(graph, priorityQueue, 0)
while (!priorityQueue.isEmpty()) {
// We have already visited vertex `edge.a`. If we have not visited `edge.b` yet, we add its outgoing edges to the PriorityQueue.
const edge = priorityQueue.extract()
if (visited.has(edge.b)) {
continue
}
minimum_spanning_tree.push(edge)
total_weight += edge.weight
visited.add(edge.b)
add_children(graph, priorityQueue, edge.b)
}
return [minimum_spanning_tree, total_weight]
}
const add_children = (
graph: [number, number][][],
priorityQueue: PriorityQueue<Edge>,
node: number
) => {
for (const out_edge of graph[node]) {
// By increasing the priority, we ensure we only add each vertex to the queue one time, and the queue will be at most size V.
priorityQueue.increasePriority(
out_edge[0],
new Edge(node, out_edge[0], out_edge[1])
)
}
}
export class Edge {
a: number = 0
b: number = 0
weight: number = 0
constructor(a: number, b: number, weight: number) {
this.a = a
this.b = b
this.weight = weight
}
}