forked from sahoo00/BoNE
-
Notifications
You must be signed in to change notification settings - Fork 0
/
UnionFind.pm
95 lines (81 loc) · 1.75 KB
/
UnionFind.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# Union-find data structure
package UnionFind;
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {};
$self->{'parent'} = {};
$self->{'rank'} = {};
bless ($self, $class);
return $self;
}
sub makeset {
my ($self, $a) = @_;
if (!defined $self->{'parent'}->{$a}) {
$self->{'parent'}->{$a} = $a;
$self->{'rank'}->{$a} = 0;
}
}
sub union {
my ($self, $a, $b) = @_;
$self->linkset($self->findset($a), $self->findset($b));
}
sub linkset {
my ($self, $a, $b) = @_;
return if (!defined $a);
return if (!defined $b);
if ($self->{'rank'}->{$a} > $self->{'rank'}->{$b}) {
$self->{'parent'}->{$b} = $a;
}
else {
$self->{'parent'}->{$a} = $b;
if ($self->{'rank'}->{$a} == $self->{'rank'}->{$b}) {
$self->{'rank'}->{$b}++;
}
}
}
sub findset {
my ($self, $a) = @_;
if (!defined $self->{'parent'}->{$a}) {
return undef;
}
if ($a ne $self->{'parent'}->{$a}) {
$self->{'parent'}->{$a} = $self->findset($self->{'parent'}->{$a});
}
return $self->{'parent'}->{$a};
}
sub delete {
my ($self, $a) = @_;
if (!defined $self->findset($a)) {
return undef;
}
my $clusters = {};
foreach my $k (keys %{$self->{'parent'}}) {
next if ($k eq $a);
push @{$clusters->{$self->findset($k)}}, $k;
}
my $set = UnionFind->new();
foreach my $k (keys %{$clusters}) {
my $key = $k;
if ($k eq $a) {
$key = $clusters->{$k}->[0];
}
$set->makeset($key);
foreach my $i (@{$clusters->{$k}}) {
$set->makeset($i);
$set->union($key, $i);
}
}
return $set;
}
1;
__END__
=head1 NAME
UnionFind - Provides Union-Find data structure
Example:
use UnionFind;
my $n = UnionFind->new();
$n->makeset($a);
$n->union($a, $b);
$n->findset($a);
=cut