在Perl中寻找欧拉路径

时间:2010-10-27 08:42:43

标签: python perl algorithm graph-theory

我有一个代码试图找到Eulerian path这样的代码。但不知怎的,它不起作用。 代码有什么问题?

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_

2 个答案:

答案 0 :(得分:1)

在Perl中,delete不会重新编制索引。从Perl documentation

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;

除此之外,测试是否存在任何未经编辑的路径存在问题:

    my $v = $stack[-1];

    if ( $graph{$v} ) {
        my $u = ( @{ $graph{$v} } )[0];

Perl和Python之间的一个区别是Perl让你处理解除引用。 $graph{$v}最初包含数组引用;只要它继续引用数组,表达式为true,此测试将始终成功。在相应的Python语句(if graph[v]:)中,它是被评估的graph[v](列表)的值。尝试:

    my $v = $stack[-1];

    if ( @{$graph{$v}} ) {
        my $u = ( @{ $graph{$v} } )[0];

开启调试

我不打算在这里给出Perl调试的基础知识(因为someone already did是Perl文档的一部分,laziness可能是一件好事),但是顺序简要介绍一下。调试的本质是在程序运行时检查数据(也称为“程序状态”)。您可以使用脚手架在程序中的各个点打印出数据(转储器对此很有用),或者使用交互式调试器来逐步执行该程序。交互式调试器是首选,因为它们为您提供更多控制并且通常更快(如果您没有在脚手架代码中打印出关键数据,则需要重新启动程序;使用调试器时,无需重新启动) 。

使用这两种技术,检查eulerPath子例程中的变量:@graph@stack$v$u。使用原始程序,用delete替换splice的中间程序,以及制作所有建议更改的程序执行此操作。看看你是否可以从数据中找出出错的地方并产生错误,然后导致我建议的更改。

答案 1 :(得分:1)

我尝试过Outis的suggestion,它按照Neversaint的要求运行:)

wget的
    http://misccb.googlecode.com/git-history/a4c46aaecbda3c103b92d0152fa2cdbdf4da4ea0/euler.pl

perl euler.pl

$ VAR1 = [       5,           4,           3,           5,           2,           3,           1,           2,           '4'         ];