Skip to content

Commit ddbb4ee

Browse files
committed
Make several improvements to the kruskalGraph method.
First, the method is now quite a bit more efficient. Rather than finding and sorting only the weights of the edges in the graph, and then searching through the graph to find those edges at each step in the algorithm, the edges with the weights are all listed and sorted by weight (more like the actual sorted edges algorithm works). So there is no need to find the edge later, you just follow the algorithm and process the edges in order. Also make the algorithm terminate once the minimal spanning tree is complete as it should. Second, the return value of the method returns more data. See the updated POD for good documentation on what is returned. This makes the method return more useful information that can be used for constructing a solution to problems using the sorted edges algorithm. These is the basically the same changes that were made for the `sortedEdgesPath` method.
1 parent e2f5cd9 commit ddbb4ee

1 file changed

Lines changed: 44 additions & 32 deletions

File tree

macros/math/SimpleGraph.pl

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,45 +1199,43 @@ sub nearestNeighborPath {
11991199
sub kruskalGraph {
12001200
my $self = shift;
12011201

1202+
my $numComponents = $self->numComponents;
12021203
my $graph = $self->copy;
12031204
my $tree = GraphTheory::SimpleGraph->new($graph->numVertices, labels => $graph->labels);
1204-
my $numTreeComponents = $tree->numComponents;
1205+
my $numTreeComponents = $tree->numVertices;
12051206

1206-
my $treeWeight = 0;
1207-
1208-
my $weight = 0;
12091207
my @treeWeights;
1208+
my $treeWeight = 0;
1209+
my @algorithmSteps;
12101210

1211-
my @weights;
1212-
for my $i (0 .. $graph->lastVertexIndex) {
1213-
for my $j ($i + 1 .. $graph->lastVertexIndex) {
1214-
push(@weights, $graph->edgeWeight($i, $j)) if $graph->hasEdge($i, $j);
1211+
my @sortedEdges;
1212+
for my $i (0 .. $self->lastVertexIndex) {
1213+
for my $j ($i + 1 .. $self->lastVertexIndex) {
1214+
next unless $self->hasEdge($i, $j);
1215+
push @sortedEdges, [ $i, $j, $self->edgeWeight($i, $j) ];
12151216
}
12161217
}
1217-
@weights = main::num_sort(@weights);
1218+
@sortedEdges = main::PGsort(sub { $_[0][-1] < $_[1][-1] }, @sortedEdges);
12181219

1219-
while (@weights > 0) {
1220-
$weight = shift @weights;
1221-
for my $i (0 .. $graph->lastVertexIndex) {
1222-
for my $j ($i + 1 .. $graph->lastVertexIndex) {
1223-
if ($graph->edgeWeight($i, $j) == $weight) {
1224-
$graph->removeEdge($i, $j);
1225-
$tree->addEdge($i, $j, $weight);
1226-
my $currentTreeNumComponents = $tree->numComponents;
1227-
if ($currentTreeNumComponents < $numTreeComponents) {
1228-
$numTreeComponents = $currentTreeNumComponents;
1229-
$treeWeight += $weight;
1230-
push @treeWeights, $weight;
1231-
} else {
1232-
$tree->removeEdge($i, $j);
1233-
}
1234-
last;
1235-
}
1236-
}
1220+
while (@sortedEdges && $numTreeComponents > $numComponents) {
1221+
my $edge = shift @sortedEdges;
1222+
my $weight = $edge->[2];
1223+
1224+
$graph->removeEdge($edge->[0], $edge->[1]);
1225+
$tree->addEdge(@$edge);
1226+
my $currentTreeNumComponents = $tree->numComponents;
1227+
if ($currentTreeNumComponents < $numTreeComponents) {
1228+
push @algorithmSteps, [ @$edge, 1 ];
1229+
$numTreeComponents = $currentTreeNumComponents;
1230+
$treeWeight += $weight;
1231+
push @treeWeights, $weight;
1232+
} else {
1233+
push @algorithmSteps, [ @$edge, 0 ];
1234+
$tree->removeEdge($edge->[0], $edge->[1]);
12371235
}
12381236
}
12391237

1240-
return ($tree, $treeWeight, \@treeWeights);
1238+
return ($tree, $treeWeight, \@treeWeights, \@algorithmSteps);
12411239
}
12421240

12431241
sub hasEulerCircuit {
@@ -2535,18 +2533,32 @@ =head2 nearestNeighborPath
25352533
25362534
=head2 kruskalGraph
25372535
2538-
($tree, $treeWeight, $treeWeights) = $graph->kruskalGraph($vertex);
2536+
($tree, $treeWeight, $treeWeights, $algorithmSteps) = $graph->kruskalGraph($vertex);
25392537
25402538
This is an implementation of Kruskal's algorithm. It attempts to find a minimum
25412539
spanning tree or forest for the graph. Note that if the graph is connected, then
25422540
the result will be a tree, and otherwise it will be a forest consisting of
25432541
minimal spanning trees for each component.
25442542
2545-
The method returns a list with three entries. The first entry is a
2543+
The method returns a list with four entries. The first entry is a
25462544
C<GraphTheory::SimpleGraph> object representing the tree or forest found. The
2547-
second entry is the total weight of that tree or forest. The last entry is a
2545+
second entry is the total weight of that tree or forest. The third entry is a
25482546
reference to an array containing the weights of the edges in the tree or forest
2549-
in the order that they are added by the algorithm.
2547+
in the order that they are added by the algorithm. The fourth entry is a
2548+
reference to an array of array references that represent the steps of Kruskal's
2549+
algorithm.
2550+
2551+
The returned representation of the steps in the algorithm will be a reference to
2552+
an array of array references where each array reference is of the form C<[$i,
2553+
$j, $weight, $accepted]>. This is where C<$i> and C<$j> are the indices of the
2554+
vertices connected by an edge in the graph, and C<$weight> is the weight of that
2555+
edge. These arrays will be sorted in ascending order of weight, i.e., the order
2556+
the edge is considered by Kruskal's algorithm. The last C<$accepted> will be
2557+
either 0 or 1. It will be 0 if the edge is rejected by the algorithm, and 1 if
2558+
it is accepted by the algorithm. Note that this list may not contain all edges
2559+
of the original graph if there are edges that are never considered by the
2560+
algorithm because the minimal spanning tree is completed before those edges are
2561+
reached.
25502562
25512563
=head2 hasEulerCircuit
25522564

0 commit comments

Comments
 (0)