Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 6a80dc7

Browse files
Added Prim's Algoritm (TheAlgorithms#227)
1 parent 9030de4 commit 6a80dc7

File tree

1 file changed

+210
-0
lines changed

1 file changed

+210
-0
lines changed

‎Graphs/PrimMST.js‎

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
// Priority Queue Helper functions
2+
function getParentPosition (position) {
3+
// Get the parent node of the current node
4+
return Math.floor((position - 1) / 2)
5+
}
6+
function getChildrenPosition (position) {
7+
// Get the children nodes of the current node
8+
return [2 * position + 1, 2 * position + 2]
9+
}
10+
11+
class PriorityQueue {
12+
// Priority Queue class using Minimum Binary Heap
13+
constructor () {
14+
this._heap = []
15+
this.keys = {}
16+
}
17+
18+
isEmpty () {
19+
// Checking if the heap is empty
20+
return this._heap.length === 0
21+
}
22+
23+
push (key, priority) {
24+
// Adding element to the queue (equivalent to add)
25+
this._heap.push([key, priority])
26+
this.keys[key] = this._heap.length - 1
27+
this._shiftUp(this.keys[key])
28+
}
29+
30+
pop () {
31+
// Removing the element with least priority (equivalent to extractMin)
32+
this._swap(0, this._heap.length - 1)
33+
const [key] = this._heap.pop()
34+
delete this.keys[key]
35+
this._shiftDown(0)
36+
return key
37+
}
38+
39+
contains (key) {
40+
// Check if a given key is present in the queue
41+
return (key in this.keys)
42+
}
43+
44+
update (key, priority) {
45+
// Update the priority of the given element (equivalent to decreaseKey)
46+
const currPos = this.keys[key]
47+
this._heap[currPos][1] = priority
48+
const parentPos = getParentPosition(currPos)
49+
const currPriority = this._heap[currPos][1]
50+
let parentPriority = Infinity
51+
if (parentPos >= 0) {
52+
parentPriority = this._heap[parentPos][1]
53+
}
54+
const [child1Pos, child2Pos] = getChildrenPosition(currPos)
55+
let [child1Priority, child2Priority] = [Infinity, Infinity]
56+
if (child1Pos < this._heap.length) {
57+
child1Priority = this._heap[child1Pos][1]
58+
}
59+
if (child2Pos < this._heap.length) {
60+
child2Priority = this._heap[child2Pos][1]
61+
}
62+
63+
if (parentPos >= 0 && parentPriority > currPriority) {
64+
this._shiftUp(currPos)
65+
} else if (child2Pos < this._heap.length &&
66+
(child1Priority < currPriority || child2Priority < currPriority)) {
67+
this._shiftDown(currPos)
68+
}
69+
}
70+
71+
_shiftUp (position) {
72+
// Helper function to shift up a node to proper position (equivalent to bubbleUp)
73+
let currPos = position
74+
let parentPos = getParentPosition(currPos)
75+
let currPriority = this._heap[currPos][1]
76+
let parentPriority = Infinity
77+
if (parentPos >= 0) {
78+
parentPriority = this._heap[parentPos][1]
79+
}
80+
81+
while (parentPos >= 0 && parentPriority > currPriority) {
82+
this._swap(currPos, parentPos)
83+
currPos = parentPos
84+
parentPos = getParentPosition(currPos)
85+
currPriority = this._heap[currPos][1]
86+
try {
87+
parentPriority = this._heap[parentPos][1]
88+
} catch (error) {
89+
parentPriority = Infinity
90+
}
91+
}
92+
this.keys[this._heap[currPos][0]] = currPos
93+
}
94+
95+
_shiftDown (position) {
96+
// Helper function to shift down a node to proper position (equivalent to bubbleDown)
97+
let currPos = position
98+
let [child1Pos, child2Pos] = getChildrenPosition(currPos)
99+
let [child1Priority, child2Priority] = [Infinity, Infinity]
100+
if (child1Pos < this._heap.length) {
101+
child1Priority = this._heap[child1Pos][1]
102+
}
103+
if (child2Pos < this._heap.length) {
104+
child2Priority = this._heap[child2Pos][1]
105+
}
106+
let currPriority
107+
try {
108+
currPriority = this._heap[currPos][1]
109+
} catch {
110+
return
111+
}
112+
113+
while (child2Pos < this._heap.length &&
114+
(child1Priority < currPriority || child2Priority < currPriority)) {
115+
if (child1Priority < currPriority && child1Priority < child2Priority) {
116+
this._swap(child1Pos, currPos)
117+
currPos = child1Pos
118+
} else {
119+
this._swap(child2Pos, currPos)
120+
currPos = child2Pos
121+
}
122+
[child1Pos, child2Pos] = getChildrenPosition(currPos)
123+
try {
124+
[child1Priority, child2Priority] = [this._heap[child1Pos][1], this._heap[child2Pos][1]]
125+
} catch (error) {
126+
[child1Priority, child2Priority] = [Infinity, Infinity]
127+
}
128+
129+
currPriority = this._heap[currPos][1]
130+
}
131+
this.keys[this._heap[currPos][0]] = currPos
132+
if (child1Pos < this._heap.length && child1Priority < currPriority) {
133+
this._swap(child1Pos, currPos)
134+
this.keys[this._heap[child1Pos][0]] = child1Pos
135+
}
136+
}
137+
138+
_swap (position1, position2) {
139+
// Helper function to swap 2 nodes
140+
[this._heap[position1], this._heap[position2]] = [this._heap[position2], this._heap[position1]]
141+
this.keys[this._heap[position1][0]] = position1
142+
this.keys[this._heap[position2][0]] = position2
143+
}
144+
}
145+
146+
class GraphWeightedUndirectedAdjacencyList {
147+
// Weighted Undirected Graph class
148+
constructor () {
149+
this.connections = {}
150+
}
151+
152+
addNode (node) {
153+
// Function to add a node to the graph (connection represented by set)
154+
this.connections[node] = {}
155+
}
156+
157+
addEdge (node1, node2, weight) {
158+
// Function to add an edge (adds the node too if they are not present in the graph)
159+
if (!(node1 in this.connections)) { this.addNode(node1) }
160+
if (!(node2 in this.connections)) { this.addNode(node2) }
161+
this.connections[node1][node2] = weight
162+
this.connections[node2][node1] = weight
163+
}
164+
165+
PrimMST (start) {
166+
// Kruskal's Algorithm to generate a Minimum Spanning Tree (MST) of a graph
167+
// Details: https://en.wikipedia.org/wiki/Prim%27s_algorithm
168+
const distance = {}
169+
const parent = {}
170+
const priorityQueue = new PriorityQueue()
171+
// Initialization
172+
for (const node in this.connections) {
173+
distance[node] = (node === start.toString() ? 0 : Infinity)
174+
parent[node] = null
175+
priorityQueue.push(node, distance[node])
176+
}
177+
// Updating 'distance' object
178+
while (!priorityQueue.isEmpty()) {
179+
const node = priorityQueue.pop()
180+
Object.keys(this.connections[node]).forEach(neighbour => {
181+
if (priorityQueue.contains(neighbour) && distance[node] + this.connections[node][neighbour] < distance[neighbour]) {
182+
distance[neighbour] = distance[node] + this.connections[node][neighbour]
183+
parent[neighbour] = node
184+
priorityQueue.update(neighbour, distance[neighbour])
185+
}
186+
})
187+
}
188+
189+
// MST Generation from the 'parent' object
190+
const graph = new GraphWeightedUndirectedAdjacencyList()
191+
Object.keys(parent).forEach(node => {
192+
if (node && parent[node]) {
193+
graph.addEdge(node, parent[node], this.connections[node][parent[node]])
194+
}
195+
})
196+
return graph
197+
}
198+
}
199+
200+
function main () {
201+
const graph = new GraphWeightedUndirectedAdjacencyList()
202+
graph.addEdge(1, 2, 1)
203+
graph.addEdge(2, 3, 2)
204+
graph.addEdge(3, 4, 1)
205+
graph.addEdge(3, 5, 100) // Removed in MST
206+
graph.addEdge(4, 5, 5)
207+
console.log(graph.PrimMST(1))
208+
}
209+
210+
main()

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /