У меня есть код, который пытается найти Эйлеровский путь. Но почему-то это не сработает. Что не так с кодом?
use strict;
use warnings;
use Data::Dumper;
use Carp;
my %graphs = ( 1 => [2,3], 2 => [1,3,4,5], 3 =>[1,2,4,5], 4 => [2,3,5], 5 => [2,3,4]);
my @path = eulerPath(%graphs);
sub eulerPath {
my %graph = @_;
# count the number of vertices with odd degree
my @odd = ();
foreach my $vert ( sort keys %graph ) {
my @edg = @{ $graph{$vert} };
my $size = scalar(@edg);
if ( $size % 2 != 0 ) {
push @odd, $vert;
}
}
push @odd, ( keys %graph )[0];
if ( scalar(@odd) > 3 ) {
return "None";
}
my @stack = ( $odd[0] );
my @path = ();
while (@stack) {
my $v = $stack[-1];
if ( $graph{$v} ) {
my $u = ( @{ $graph{$v} } )[0];
push @stack, $u;
# Find index of vertice v in graph{$u}
my @graphu = @{ $graph{$u} }; # This is line 54.
my ($index) = grep $graphu[$_] eq $v, 0 .. $#graphu;
delete @{ $graph{$u} }[$index];
delete @{ $graph{$v} }[0];
}
else {
push @path, pop(@stack);
}
}
print Dumper \@path;
return @path;
}
Ошибка, которую я получаю:
Use of uninitialized value in hash element at euler.pl line 54
Я ожидаю, что он вернет результат следующим образом:
$VAR = [5, 4, 3, 5, 2, 3, 1, 2, 4];
На самом деле я попытался подражать рабочему коду в Python:
def eulerPath(graph):
# counting the number of vertices with odd degree
odd = [ x for x in graph.keys() if len(graph[x])&1 ]
print odd
odd.append( graph.keys()[0] )
if len(odd) > 3:
return None
stack = [ odd[0] ]
path = []
# main algorithm
while stack:
v = stack[-1]
if graph[v]:
u = graph[v][0]
stack.append(u)
# deleting edge u-v
#print graph[u][ graph[u].index(v) ]
#print graph[u].index(v)
del graph[u][ graph[u].index(v) ]
del graph[v][0]
else:
path.append( stack.pop() )
return path
stack_ = eulerPath({ 1:[2,3], 2:[1,3,4,5], 3:[1,2,4,5], 4:[2,3,5], 5:[2,3,4] })
print stack_
В Perl delete
не переиндексируется. Из документации Perl :
delete() также может использоваться на массивах и средах массива, но его поведение менее прямолинейно. Хотя exists() вернет false для удаленных записей, удаление элементов массива никогда не изменяет индексы существующих значений; используйте shift() или splice() для этого.
Как указано в документации, вы можете использовать splice
для удаления и повторной индексации.
my @graphu = @{ $graph{$u} }; # This is line 54.
my ($index) = grep $graphu[$_] eq $v, 0 .. $#graphu;
splice @{ $graph{$u} }, $index, 1;
splice @{ $graph{$v} }, 0, 1;
В дополнение к этому существует проблема с проверкой того, имеет ли node все неиспользуемые пути:
my $v = $stack[-1];
if ( $graph{$v} ) {
my $u = ( @{ $graph{$v} } )[0];
Одно отличие между Perl и Python заключается в том, что Perl заставляет вас обрабатывать разыменование. $graph{$v}
изначально содержит ссылку на массив; пока он продолжает ссылаться на массив, выражение истинно, и этот тест всегда будет успешным. В соответствующем операторе Python (if graph[v]:
) это значение graph[v]
(списка), которое оценивается. Попробуйте:
my $v = $stack[-1];
if ( @{$graph{$v}} ) {
my $u = ( @{ $graph{$v} } )[0];
Я не буду описывать основы отладки Perl здесь (поскольку кто-то уже сделал как часть документации Perl, а laziness может быть хорошей вещью), но краткий обзор выглядит по порядку. Суть отладки заключается в анализе данных (ака "состояние программы" ) в программе по мере ее запуска. Вы можете сделать это с помощью лесов, которые распечатывают данные в разных точках программы (для этого полезно использовать Dumper), или с помощью интерактивного отладчика для перехода через программу. Интерактивные отладчики предпочтительнее, потому что они дают вам больше контроля и, как правило, быстрее (если вы не распечатывали важную часть данных в коде эшафота, вам нужно перезапустить программу, а отладчик, не нужно перезапускать),
Используя любой из этих методов, рассмотрите переменные в вашей подпрограмме eulerPath
: @graph
, @stack
, $v
, $u
. Сделайте это как с вашей исходной программой, так и с промежуточной программой, которая заменяет delete
на splice
, а также с программой, в которой внесены все мои предложенные изменения. Посмотрите, можете ли вы выяснить из данных, что происходит не так, и порождать ошибки, и что затем приводит к изменениям, которые я предлагал.
Я попробовал Outis предложение, и он работает по желанию Невершина:)
Wget
http://misccb.googlecode.com/git-history/a4c46aaecbda3c103b92d0152fa2cdbdf4da4ea0/euler.pl
perl euler.pl
$ VAR1 = [ 5, 4, 3, 5, 2, 3, 1, 2, '4' ];