tsort.pl

From Club Ubuntu

Jump to: navigation, search
use strict;
use warnings;
use Data::Dumper;

sub clean(\%) {
  my $graph = shift;
  for (values %$graph) {
    @$_ = keys %{ { map { $_, 1 } @$_ } };
    $graph->{$_} ||= [] for @$_;
  }
  return %$graph;
}

sub unconnected(%) {
  my %graph = @_;
  delete @graph{map { @$_ } values %graph};
  return keys %graph;
}

sub merge_into(\%%) {
  my ($graph1, %graph2) = @_;
  push @{$graph1->{$_}}, @{$graph2{$_}} for keys %graph2;
  clean %$graph1;
}

sub toposort(\%;\@) {
  my ($graph, $remaining_nodes) = @_;
  my %graph = %$graph;

  my @items;

  while (my @unconnected = unconnected %graph) {
    my @sched = splice(@unconnected, 0, scalar @unconnected);
    push @items, [@sched];
    delete @graph{@sched};
  }

  @$remaining_nodes = keys %graph if defined $remaining_nodes;

  return @items;
}

sub prio_graph(%) {
  my %prio = @_;
  my @prio = @prio{sort {$a <=> $b} keys %prio};

  return unless @prio;

  my %graph;

  for my $i (0 .. $#prio) {
    my ($current, @next) = @prio[$i .. $#prio];
    for (@$current) {
      push @{$graph{$_}}, map { @$_ } @next;
    }
  }

  return clean %graph;
}

my %graph = (
  a => ['b', 'q'],
  b => ['c'],
  d => ['e'],
  q => ['d'],
  x => ['y'],
  y => ['x'] );

clean %graph;

my %prio = (5 => ['q', 'e'], 7 => [], 10 => ['z', 'f', 'r']);

merge_into %graph, prio_graph(%prio);

my @items = toposort %graph, my @cyclical;

print Dumper(\@items, \@cyclical), "\n";

%graph = ('A' => ['B'], 'B' => ['C'], M => ['N'], X => ['Y'], 'Y' => ['Z']);
clean %graph;

my @items = toposort %graph;

print Dumper(\@items);
Personal tools
community