| Michael Styer on 14 Dec 2004 04:44:36 -0000 |
|
Jeff Abrahamson wrote:
> On Sun, Dec 12, 2004 at 10:27:11PM -0500, Michael Styer wrote:
>> [85 lines, 432 words, 2550 characters] Top characters: etsnoarh
>>
>> I've been looking at this code wondering what the heck is going on,
>> and I can't make any sense of it, so I'll ask.
>
> Yes, it's a bit odd looking, I admit, and it's doing something you
> might not think about very often.
>
> Here's the algorithm in pseudo-code. It finds the connected
> components of an undirected graph. Cf. Cormen et al., ch 22 (first
> edition) or ch 21 (second edition).
<snip helpful quote from Cormen et al>
> The algorithm for connected components is then
>
> for each vertex v in V(G)
> make-set(v)
> for each edge (u,v) in E(G)
> if find-set(u) != find_set(v)
> union(u,v)
>
> Quoting from Cormen again, the procedure initially places each vertex
> v in its own set. Then, for each edge (u, v), it unites the sets
> containing u and v. After all the edges are processed, two vertices
> are in the same connected component if and only if the corresponding
> objects are in the same set.
>
>
> So the thing I need is to say "which set is x in?"
Aha. OK, I see what the issue is, and what you were doing. Thank you for
the explanation and references.
> Thus, I have a hash that has elements as keys and references to (I was
> hoping pointers to) hashes as values. A union is thus just a matter
> of adding one element's hash's keys to the other's, then setting the
> two hash pointers to the same hash reference.
> It would have worked in C. ;-)
My C is, um, not very good, so I've taken a stab your Perl code
instead... ;)
What about this? (+ to add a line, - to delete, hope that's obvious) Does
this do what you want? (Warning: this is not tested)
my %sets = ();
for my $v (keys %V) {
- $sets{$v} = [$v];
+ $sets{$v} = {$v => 1}
}
for my $v_begin (keys %E) {
my $adj = $E{$v_begin};
for my $v_end (keys %{$adj}) {
if($sets{$v_begin} != $sets{$v_end}) {
# union of sets
my %s1 = %{$sets{$v_begin}};
my %s2 = %{$sets{$v_end}};
+ my $union = {};
- for my $key (keys %s1) {
+ for my $key (keys %s1, keys %s2) {
- $s2{$key} = 1;
+ $union->{$key} = 1;
+ $sets{$key} = $union;
}
- $sets{$v_begin} = $sets{$v_end}; # set pointers equal
}
}
}
my %unique_sets;
for my $s (keys %sets) {
print $sets{$s}, "\n";
$unique_sets{$sets{$s}} = $sets{$s};
print $sets{$s}, "\n";
}
Or see the attachment for a version with subroutines and what have you. I
wrote that first to figure out what you were trying to do, then realized
that what I had was almost exactly what you started with and you just
need the changes above. I think. :) I've never used the stringification
of a reference like this, but it seems like it should work for what
you're doing...
Mike
Attachment:
connected_components.pl
|
|