File Coverage

blib/lib/Graph/UnionFind.pm
Criterion Covered Total %
statement 43 43 100.0
branch 23 28 82.1
condition 2 6 33.3
subroutine 9 9 100.0
pod 5 5 100.0
total 82 91 90.1


line stmt bran cond sub pod time code
1             package Graph::UnionFind;
2              
3 7     7   121201 use strict;
  7         17  
  7         286  
4 7     7   44 use warnings;
  7         11  
  7         5780  
5              
6             sub _PARENT () { 0 }
7             sub _RANK () { 1 }
8              
9             sub new {
10 31     31 1 267437 my $class = shift;
11 31         118 bless { }, $class;
12             }
13              
14             sub add {
15 507     507 1 1469 my ($self, @elems) = @_;
16 507         2065 @elems = grep !defined $self->{$_}, @elems;
17 507         1886 @$self{ @elems } = map [ $_, 0 ], @elems;
18             }
19              
20             sub _parent {
21 18487 50   18487   36119 return undef unless defined $_[1];
22 18487 50 33     57383 Graph::__carp_confess(__PACKAGE__ . "::_parent: bad arity") if @_ < 2 or @_ > 3;
23 18487 100       32441 if (@_ == 2) {
24 14863 100       53846 exists $_[0]->{ $_[ 1 ] } ? $_[0]->{ $_[1] }->[ _PARENT ] : undef;
25             } else {
26 3624         7939 $_[0]->{ $_[1] }->[ _PARENT ] = $_[2];
27             }
28             }
29              
30             sub _rank {
31 1008 50   1008   2019 return unless defined $_[1];
32 1008 50 33     3374 Graph::__carp_confess(__PACKAGE__ . "::_rank: bad arity") if @_ < 2 or @_ > 3;
33 1008 100       1822 if (@_ == 2) {
34 968 50       2385 exists $_[0]->{ $_[1] } ? $_[0]->{ $_[1] }->[ _RANK ] : undef;
35             } else {
36 40         176 $_[0]->{ $_[1] }->[ _RANK ] = $_[2];
37             }
38             }
39              
40             sub find {
41 5290     5290 1 10947 my ($self, @v) = @_;
42 5290         7455 my @ret;
43 5290         8856 for my $x (@v) {
44 7433 100       13347 push(@ret, undef), next unless defined(my $px = $self->_parent($x));
45 7430 100       17555 $self->_parent( $x, $self->find( $px ) ) if $px ne $x;
46 7430         16129 push @ret, $self->_parent( $x );
47             }
48 5290         16386 @ret;
49             }
50              
51             sub union {
52 475     475 1 903 my ($self, @edges) = @_;
53 475         1843 $self->add(map @$_, @edges);
54 475         1036 for my $e (@edges) {
55 500         1080 my ($px, $py) = $self->find( @$e );
56 500 100       1333 next if $px eq $py;
57 484         972 my $rx = $self->_rank( $px );
58 484         995 my $ry = $self->_rank( $py );
59             # print "union($x, $y): px = $px, py = $py, rx = $rx, ry = $ry\n";
60 484 100       914 if ( $rx > $ry ) {
61 425         821 $self->_parent( $py, $px );
62             } else {
63 59         155 $self->_parent( $px, $py );
64 59 100       235 $self->_rank( $py, $ry + 1 ) if $rx == $ry;
65             }
66             }
67             }
68              
69             sub same {
70 1622     1622 1 3249 my ($uf, $u, $v) = @_;
71 1622         3459 my ($fu, $fv) = $uf->find($u, $v);
72 1622 100       4950 return undef if grep !defined, $fu, $fv;
73 1621         5570 $fu eq $fv;
74             }
75              
76             1;
77             __END__