Skip to content

Commit 55d91f8

Browse files
authored
Add Minimum Spanning Tree in PowerShell (TheRenegadeCoder#4858)
1 parent 7761c90 commit 55d91f8

File tree

1 file changed

+144
-0
lines changed

1 file changed

+144
-0
lines changed
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
function Show-Usage() {
2+
Write-Host "Usage: please provide a comma-separated list of integers"
3+
Exit(1)
4+
}
5+
6+
function Parse-IntList([string]$Str) {
7+
@($Str.Split(",") | ForEach-Object { [int]::Parse($_) })
8+
}
9+
10+
class NodeItem {
11+
[int]$Index
12+
[int]$Weight
13+
14+
NodeItem([int]$index, [int]$weight) {
15+
$this.Index = $index
16+
$this.Weight = $weight
17+
}
18+
}
19+
20+
class Node {
21+
[int]$Index
22+
[NodeItem[]]$Children
23+
24+
Node([int]$index) {
25+
$this.Index = $index
26+
$this.Children = @()
27+
}
28+
29+
[void] AddChild([int]$index, [int]$weight) {
30+
$this.Children += [NodeItem]::new($index, $weight)
31+
}
32+
}
33+
34+
function Create-Graph([array]$Weights, [int]$NumVertices) {
35+
# Initialize nodes
36+
$nodes = 0..($NumVertices - 1) | ForEach-Object { [Node]::new($_) }
37+
38+
# Get neighbors for this node based on weights
39+
$index = 0
40+
for ($row = 0; $row -lt $NumVertices; $row++) {
41+
for ($col = 0; $col -lt $NumVertices; ($col++), ($index++)) {
42+
if ($Weights[$index] -gt 0) {
43+
$nodes[$row].AddChild($col, $Weights[$index])
44+
}
45+
}
46+
}
47+
48+
$nodes
49+
}
50+
51+
class MstItem {
52+
[int]$SrcIndex
53+
[int]$DestIndex
54+
[int]$Weight
55+
56+
MstItem([int]$srcIndex, [int]$destIndex, [int]$weight) {
57+
$this.SrcIndex = $srcIndex
58+
$this.DestIndex = $destIndex
59+
$this.Weight = $weight
60+
}
61+
}
62+
63+
# Prim's Minimum Spanning Tree (MST) Algorithm based on C implementation of
64+
# https://www.geeksforgeeks.org/prims-minimum-spanning-tree-mst-greedy-algo-5/
65+
function Invoke-PrimMst([Node[]]$Graph) {
66+
$numVertices = $Graph.Length
67+
68+
# Array to store constructed MST. Indicate no parents yet
69+
$parents = @(-1) * $numVertices
70+
71+
# Key values used to pick minimum weight edge. Initialize to infinity
72+
$keys = @([int]::MaxValue) * $numVertices
73+
74+
# Indicate nothing in MST yet
75+
$mstSet = @($false) * $numVertices
76+
77+
# Include first vertex in MST
78+
$keys[0] = 0
79+
80+
# The MST will include all vertices
81+
for ($i = 1; $i -lt $numVertices; $i++) {
82+
# Pick index of the minimum key value not already in MST
83+
$u = Find-MinKey $keys $mstSet
84+
85+
# Add picked vertex to MST
86+
$mstSet[$u] = $true
87+
88+
# Update key values and parent indices of picked adjacent
89+
# vertices. Only consider vertices not yet in MST
90+
foreach ($child in $Graph[$u].Children) {
91+
$v = $child.Index
92+
$w = $child.Weight
93+
if (-not $mstSet[$v] -and $w -lt $keys[$v]) {
94+
$parents[$v] = $u
95+
$keys[$v] = $w
96+
}
97+
}
98+
}
99+
100+
# Construct MST information to return, skipping over root
101+
@(1..($numVertices - 1) | ForEach-Object { [MstItem]::new($parents[$_], $_, $keys[$_]) })
102+
}
103+
104+
function Find-MinKey([int[]]$Keys, [bool[]]$MstSet) {
105+
$minValue = [int]::MaxValue
106+
$minIndex = -1
107+
for ($v = 0; $v -lt $Keys.Length; $v++) {
108+
if ($Keys[$v] -lt $minValue -and -not $MstSet[$v]) {
109+
$minValue = $Keys[$v]
110+
$minIndex = $v
111+
}
112+
}
113+
114+
$minIndex
115+
}
116+
117+
function Invoke-MstTotalWeight([MstItem[]]$mst) {
118+
($mst.Weight | Measure-Object -Sum).Sum
119+
}
120+
121+
if ($args.Length -lt 1 -or -not $args[0]) {
122+
Show-Usage
123+
}
124+
125+
try {
126+
$weights = Parse-IntList $args[0]
127+
} catch {
128+
Show-Usage
129+
}
130+
131+
$numVertices = [int][Math]::Floor([Math]::Sqrt($weights.Length))
132+
if ($weights.Length -ne $numVertices * $numVertices) {
133+
Show-Usage
134+
}
135+
136+
# Create graph from weights
137+
$graph = Create-Graph $weights $numVertices
138+
139+
# Get MST using Prim's algorithm
140+
$mst = Invoke-PrimMst $graph
141+
142+
# Calculate total weight of MST
143+
$totalWeight = Invoke-MstTotalWeight $mst
144+
Write-Output $totalWeight

0 commit comments

Comments
 (0)