File Coverage

blib/lib/Graph/Kruskal.pm
Criterion Covered Total %
statement 9 133 6.7
branch 0 28 0.0
condition 0 12 0.0
subroutine 3 12 25.0
pod 0 9 0.0
total 12 194 6.1


line stmt bran cond sub pod time code
1              
2             # Copyright (c) 1995, 1996, 1997 by Steffen Beyer. All rights reserved.
3             # This package is free software; you can redistribute it and/or modify
4             # it under the same terms as Perl itself.
5              
6             package Graph::Kruskal;
7              
8 1     1   709 use strict;
  1         3  
  1         47  
9 1         219 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION
10 1     1   6 $number_of_edges $number_of_vortices @V @E @T);
  1         2  
11              
12             require Exporter;
13              
14             @ISA = qw(Exporter);
15              
16             @EXPORT = qw();
17              
18             @EXPORT_OK = qw(define_vortices define_edges
19             heapify makeheap heapsort
20             find union kruskal example);
21              
22             %EXPORT_TAGS = (all => [@EXPORT_OK]);
23              
24             $VERSION = '2.0';
25              
26 1     1   5 use Carp;
  1         4  
  1         1420  
27              
28             $number_of_vortices = 0;
29             $number_of_edges = 0;
30              
31             sub example
32             {
33 0     0 0   my($costs) = 0;
34 0           my($k);
35              
36 0           print "\n";
37 0           print "+++ Kruskal's Algorithm for Minimal Spanning Trees in Graphs +++";
38 0           print "\n";
39              
40 0           &define_vortices(2,3,5,7,11,13,17,19,23,29,31);
41              
42 0           print "\nVortices:\n\n";
43              
44 0           for ( $k = 1; $k <= $#V; ++$k )
45             {
46 0 0         if (defined $V[$k]) { print "$k\n"; }
  0            
47             }
48              
49 0           &define_edges( 2,13,3, 3,13,2, 5,13,1, 3,5,2, 3,29,21, 23,29,3,
50             23,31,2, 5,31,15, 5,7,10, 2,11,2, 7,11,2, 7,19,5, 11,19,2,
51             7,31,4, 3,17,3, 17,23,3, 7,17,3 );
52              
53 0           print "\nEdges:\n\n";
54              
55 0           for ( $k = 1; $k <= $#E; ++$k )
56             {
57 0           print ${$E[$k]}{'from'}, " <-> ", ${$E[$k]}{'to'}, " = ",
  0            
  0            
58 0           ${$E[$k]}{'cost'}, "\n";
59             }
60              
61 0           &kruskal();
62              
63 0           print "\nEdges in minimal spanning tree:\n\n";
64              
65 0           for ( $k = 1; $k <= $#T; ++$k )
66             {
67 0           print ${$T[$k]}{'from'}, " <-> ", ${$T[$k]}{'to'}, " = ",
  0            
  0            
68 0           ${$T[$k]}{'cost'}, "\n";
69 0           $costs += ${$T[$k]}{'cost'};
  0            
70             }
71              
72 0           print "\nTotal costs: $costs\n\n";
73             }
74              
75             sub define_vortices
76             {
77 0     0 0   undef @V;
78 0           $number_of_vortices = 0;
79 0           foreach (@_)
80             {
81 0 0         ($_ > 0) || croak "Graph::Kruskal::define_vortices(): vortex number not positive\n";
82 0           $V[$_] = -1;
83 0           ++$number_of_vortices;
84             }
85             }
86              
87             sub define_edges
88             {
89 0     0 0   my($from,$to,$cost);
90              
91 0           undef @E;
92 0           $number_of_edges = 0;
93 0           while (@_)
94             {
95 0   0       $from = shift || croak "Graph::Kruskal::define_edges(): missing 'from' vortex number\n";
96 0   0       $to = shift || croak "Graph::Kruskal::define_edges(): missing 'to' vortex number\n";
97 0   0       $cost = shift || croak "Graph::Kruskal::define_edges(): missing edge 'cost' value\n";
98 0 0         defined $V[$from] || croak "Graph::Kruskal::define_edges(): vortex '$from' not previously defined\n";
99 0 0         defined $V[$to] || croak "Graph::Kruskal::define_edges(): vortex '$to' not previously defined\n";
100 0 0         ($from != $to) || croak "Graph::Kruskal::define_edges(): vortices 'from' and 'to' are the same\n";
101 0           $E[++$number_of_edges] =
102             { 'from' => $from, 'to' => $to, 'cost' => $cost };
103             }
104             }
105              
106             sub heapify # complexity: O(ld n)
107             {
108 0     0 0   my($i,$n) = @_;
109 0           my($i2,$i21,$j,$swap);
110              
111 0           while ($i < $n)
112             {
113 0           $j = $i;
114 0           $i2 = $i * 2;
115 0           $i21 = $i2 + 1;
116 0 0         if ($i2 <= $n)
117             {
118 0 0         if (${$E[$i]}{'cost'} > ${$E[$i2]}{'cost'})
  0            
  0            
119             {
120 0           $j = $i2;
121 0 0         if ($i21 <= $n)
122             {
123 0 0         if (${$E[$i2]}{'cost'} > ${$E[$i21]}{'cost'}) { $j = $i21; }
  0            
  0            
  0            
124             }
125             }
126             else
127             {
128 0 0         if ($i21 <= $n)
129             {
130 0 0         if (${$E[$i]}{'cost'} > ${$E[$i21]}{'cost'}) { $j = $i21; }
  0            
  0            
  0            
131             }
132             }
133             }
134 0 0         if ($i != $j)
135             {
136 0           $swap = $E[$i];
137 0           $E[$i] = $E[$j];
138 0           $E[$j] = $swap;
139 0           $i = $j;
140             }
141 0           else { $i = $n; }
142             }
143             }
144              
145             sub makeheap # complexity: O(n ld n)
146             {
147 0     0 0   my($n) = @_;
148 0           my($k);
149              
150 0           for ( $k = $n - 1; $k > 0; --$k ) { &heapify($k, $n); }
  0            
151             }
152              
153             # The following subroutine isn't used by this algorithm, it is only included
154             # here for the sake of completeness:
155              
156             sub heapsort # complexity: O(n ld n)
157             {
158 0     0 0   my($n) = @_;
159 0           my($k,$swap);
160              
161 0           for ( $k = $n - 1; $k > 0; --$k ) { &heapify($k, $n); }
  0            
162              
163 0           for ( $k = $n; $k > 1; --$k )
164             {
165 0           $swap = $E[1];
166 0           $E[1] = $E[$k];
167 0           $E[$k] = $swap;
168 0           &heapify(1, $k - 1);
169             }
170             }
171              
172             sub find
173             {
174 0     0 0   my($i) = @_;
175 0           my($j,$k,$t);
176              
177 0           $j = $i;
178 0           while ($V[$j] > 0) { $j = $V[$j]; } # find root element (= set identifier)
  0            
179 0           $k = $i;
180 0           while ($k != $j) # height compression of the tree
181             {
182 0           $t = $V[$k];
183 0           $V[$k] = $j;
184 0           $k = $t;
185             }
186 0           return($j);
187             }
188              
189             sub union
190             {
191 0     0 0   my($i,$j) = @_;
192 0           my($x);
193              
194 0           $x = $V[$i] + $V[$j]; # calculate number of elements in resulting set
195 0 0         if ($V[$i] > $V[$j]) # which of the two sets contains more elements?
196             {
197 0           $V[$i] = $j; # merge them
198 0           $V[$j] = $x; # update number of elements
199             }
200             else
201             {
202 0           $V[$j] = $i; # merge them
203 0           $V[$i] = $x; # update number of elements
204             }
205             }
206              
207             sub kruskal # complexity: O(n ld n) ( where n := |{ Edges }| )
208             {
209 0     0 0   my($n) = $number_of_edges;
210 0           my($v) = $number_of_vortices;
211 0           my($i,$j,$swap);
212 0           my($t) = 0;
213              
214 0           undef @T;
215 0           &makeheap($number_of_edges); # complexity: O(n ld n)
216 0   0       while (($v > 1) && ($n > 0))
217             {
218 0           $swap = $E[1];
219 0           $E[1] = $E[$n];
220 0           $E[$n] = $swap;
221 0           &heapify(1, $n - 1); # complexity: n O(ld n) = O(n ld n)
222 0           $i = find(${$E[$n]}{'from'}); # complexity: n ( 2 find + 1 union ) =
  0            
223 0           $j = find(${$E[$n]}{'to'}); # O( G(n) n ) <= O(n ld n)
  0            
224 0 0         if ($i != $j)
225             {
226 0           union($i,$j);
227 0           $T[++$t] = $E[$n];
228 0           --$v;
229             }
230 0           --$n;
231             }
232 0           return(@T);
233             }
234              
235             1;
236              
237             __END__