что не так с моим алгоритмом Дейкстры для ненаправленного графа с одинаковым весом в perl. это не перестает повторяться

У меня есть взвешенный график для белковых узлов. Я писал программу на Perl, чтобы найти кратчайший путь для данного узла, используя алгоритм Дейкстры. Каждый белок (вершина) имеет одинаковый вес. Моя программа не останавливает итерацию и не дает мне никакого результата. Я не знаю, что вызывает проблему.

Моя идея состоит в том, чтобы получить имя узла белка от пользователя и начать поиск кратчайшего пути, используя данный белок в качестве корневого узла.

%graph = (
  'A' => {'B' => 1, 'C' => 5},
  'B' => {'C' => 4, 'D' => 2},
  'C' => {'A' => 1, 'B' => 3},
  'D' => {'C' => 2, 'B' => 3}
);

sub dijkstra {
    print "Enter a node\n";
    my $root= <>;
    my $infinity = "inf";
    my %graph= %graph;
    my %dist;
    my %prev;
    ############################ the algorithm ####
    # first, set all distances to infinity
    foreach $n (keys %graph) { $dist{$n} = $infinity; $prev{$n}=$n; }
    # .. except the source
    $dist{$root} = 0;
    # loop while we have unsolved nodes
    # sort unsolved by distance from root
    foreach my $n1 (sort keys %graph) {
        foreach my $n2 (keys %{$graph{$n1}}) {
            if (($dist{$n2} eq $infinity) ||
                ($dist{$n2} > ($dist{$n1} + $graph{$n1}{$n2}) )) {
                $dist{$n2} = $dist{$n} + $graph{$n1}{$n2};
                $prev{$n2} = $n1;
            }
        }
    }
    ##### print the solutions ######
    my $path;
    foreach $n(keys %graph) {
        my $t = $n;
        $path = $t;
        while ($t ne $root) { $t = $prev{$t}; $path = "$t -> " . $path; }
        print "$n\t$dist{$n}\t$path\n";
    }
}
dijkstra();

person Michael.Z    schedule 28.12.2011    source источник
comment
пример кода неполный без примеров данных (значение глобального %graph).   -  person outis    schedule 28.12.2011


Ответы (1)


Когда вы читаете ввод с помощью <>, он включает завершающий символ новой строки. В результате он не равен ни одному из ключей в %graph (которые предположительно не имеют символов новой строки). Быстрое исправление заключается в chomp корневом каталоге.

...
my $root = <>;
chomp $root;

Полное исправление состоит в том, чтобы проверить, что $root является допустимой вершиной, и вывести ошибку, если это не так. Обратите внимание, что вы не должны обрабатывать пользовательский ввод и логику приложения в одной и той же функции. Отдельные проблемы для уменьшения связь.

Кроме того, глобальные значения плохи. Переменные пакета не так уж и плохи, если это то, что вы делаете, но %group следует передать dijkstra (как ссылка), поэтому реализация не так тесно связана с графом. Передача графа в качестве параметра усложняет код.

Обратите внимание, что вам не нужно определять свою собственную бесконечность. В Perl есть inf-inf).

sub dijkstra {
    my ($graph, $root) = @_;
    my (%dist, %prev);

    ############################ the algorithm ####
    # first, set all distances to infinity
    foreach $n (keys %{$graph}) { $dist{$n} = inf; $prev{$n}=$n; }
    # .. except the source
    $dist{$root} = 0;

    # loop while we have unsolved nodes
    # sort unsolved by distance from root
    foreach my $n1 (sort keys %{$graph}) {
        foreach my $n2 (keys %{$graph->{$n1}}) {
            if (($dist{$n2} eq inf) ||
                ($dist{$n2} > ($dist{$n1} + $graph->{$n1}{$n2}) )) {
                $dist{$n2} = $dist{$n} + $graph->{$n1}{$n2};
                $prev{$n2} = $n1;
            }
        }
    }
    return (\%prev, \%dist);
}

sub getNode {
    my $graph = shift;
    print "Enter a node\n";
    my $root= <>;
    chomp $root;
    if (! exists $graph->{$root}) {
        die("'$root' isn't a valid node.\n");
    }
    return $root;
}

sub printPaths {
    my ($graph, $prev, $dist) = @_;
    my $path;

    foreach $n (keys %{$graph}) {
        my $t = $n;
        $path = $t;
        while ($t ne $root) {
            $t = $prev->{$t}; $path = "$t -> " . $path;
        }
        print "$n\t$dist->{$n}\t$path\n";
    }
}

$graph = {
  'A' => {'B' => 1, 'C' => 5},
  'B' => {'C' => 4, 'D' => 2},
  'C' => {'A' => 1, 'B' => 3},
  'D' => {'C' => 2, 'B' => 3}
};
$root = getNode($graph);
#($prev, $dist) = dijkstra(\%graph, $root);
#printPaths($graph, $prev, $dist);
# or, for obfuscation:
printPaths($graph, dijkstra($graph, $root));

Для отладки чего-то подобного можно использовать скаффолдинг (распечатывать отладочные сообщения в разных точках кода; Data::Dumper полезен для этого). А еще лучше научиться пользоваться интерактивным отладчиком.

person outis    schedule 28.12.2011
comment
спасибо, чувак, но у меня все еще есть проблема, когда я пытаюсь сослаться на свой график, обычно я просто ссылаюсь на свой график, который я уже реализовал, читая из файла и помещая его в хеш. - person Michael.Z; 28.12.2011
comment
@Michael.Z: SO — это сайт вопросов и ответов, а не форум. Если у вас есть другой вопрос, разместите его как таковой после поиска, чтобы убедиться, что он не дублируется. Вы можете вернуться к этому вопросу (или ответу) в своем новом вопросе, если хотите предоставить контекст. Убедитесь, что любые примеры кода в вашем новом вопросе сведены к минимуму: они полны и лаконичны. - person outis; 29.12.2011
comment
Прочтите часто задаваемые вопросы, если вы еще этого не сделали, чтобы ознакомиться с тем, как работает SO. Это не то, что вы думаете. - person outis; 29.12.2011