use strict; my %graph = ( FOO => [qw/BAR BLAH ASDF/], BAR => [qw/LA/], BLAH => [qw/XYZ/], ASDF => [qw/OOOOO/], LA => [], XYZ => [qw/LA/], OOOOO => [] ); my %reversegraph; for my $x (keys %graph) { for my $y (@{ $graph{$x} }) { push @{$reversegraph{$y}}, $x; } } { my %seen; my %onstack; my @list; sub how_to_uninstall { my $target = shift; (@list, %seen, %onstack) = (); _traverse(\%reversegraph, $target); my @dependedontarget = @list; (@list, %seen, %onstack) = (); for my $v (@dependedontarget) { _traverse(\%graph, $v) unless $seen{$v}; } return @list; } sub _traverse { my ($G,$x) = @_; $seen{$x} = $onstack{$x} = 1; for my $y (@{$G->{$x}}) { die "cyclic!" if $onstack{$y}; # back edge _traverse($G,$y) unless $seen{$y}; } push @list, $x; $onstack{$x} = 0; } } my @order = how_to_uninstall('BLAH'); print "@order\n"; __OUTPUT__ LA BAR XYZ BLAH OOOOO ASDF FOO