Исправлена ​​функция для вычислений на графике

У меня есть график:

Вот данные:

$nodes = [
        'f' => ['d g'],
        'b' => ['a d'],
        'g' => ['i'],
        'd' => ['c e'],
        'i' => ['h']
    ];

Функция ниже пытается найти узлы между двумя предоставленными узлами:

function findPathBetweenNodes($start, $end, $nodes) {
        
        foreach ($nodes as $node => $edges) {
            $nodes[$node] = explode(' ', $edges[0]);
        }

        function searchPath($current, $end, $nodes, &$visited) {
            if ($current === $end) {
                return [$current];
            }
            
            $visited[$current] = true;
            foreach ($nodes as $node => $children) {
                if (in_array($current, $children) && !isset($visited[$node])) {
                    $path = searchPath($node, $end, $nodes, $visited);
                    if ($path) {
                        return array_merge([$current], $path);
                    }
                }
            }
            return null;
        }

        $visited = [];
        $path = searchPath($start, $end, $nodes, $visited);

        if ($path) {
            array_shift($path); 
            array_pop($path);   
        }

        return $path ?: []; 
    }

Тестовый пример: print_r(findPathBetweenNodes('h', 'f', $nodes)); Возвращает правильный результат:

Array
(
    [0] => i
    [1] => g
)

Тестовый пример: print_r(findPathBetweenNodes('f', 'h', $nodes)); Вернуть пустой массив.

Тестовый пример: print_r(findPathBetweenNodes('a', 'c', $nodes)); Возвращает пустой массив.

Как исправить функцию, чтобы она работала и в других случаях? Спасибо.

Ради здравомыслия людей, читающих ваш код, не определяйте именованные функции внутри других функций.

Sammitch 08.04.2024 22:38

Является ли этот граф направленным или неориентированным? В вашей диаграмме используются стрелки, но ваш «правильный» пример проходит обратный путь между «начальным» и «конечным» узлами.

Sammitch 08.04.2024 22:43

@Sammith - Направление графика не имеет значения.

XTRUST.ORG 08.04.2024 22:56

Вы не использовали слово «правильный» для описания двух вторых тестовых случаев; так можем ли мы предположить, что эти результаты неверны? Хотите a, чтобы c вернуться ['b', 'd']? Я считаю, что ваше объяснение и требования неясны. Что означает How to fix a function to make it work in other cases too?? Пожалуйста, предоставьте больше тестовых примеров и желаемый результат для каждого (покажите достаточно сложные случаи, чтобы исключить двусмысленность).

mickmackusa 08.04.2024 23:50

Я думаю, что есть причина для беспокойства по поводу желаемого вывода, потому что, когда два входных узла напрямую соединены, желаемым результатом является пустой массив (в пути не требуются дополнительные соединения), И когда два входных узла не имеют соединения, желаемый результат результат — пустой массив. Эти неоднозначные результаты не кажутся пригодными для использования в реальном приложении.

mickmackusa 09.04.2024 00:28

Отвечает ли это на ваш вопрос? Поиск путей в неориентированном графе

Olivier 09.04.2024 09:24

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

mickmackusa 09.04.2024 21:09
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
4
7
70
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Массив $nodes не настроен как неориентированный граф. На изображении показано, что так и должно быть.

$nodes = [
    'a' => ['b'],
    'b' => ['a d'],
    'c' => ['d'],
    'd' => ['b c e f'],
    'e' => ['d'],
    'f' => ['d g'],
    'g' => ['f i'],
    'h' => ['i'],
    'i' => ['g h']
];

Для print_r(findPathBetweenNodes('f', 'h', $nodes));

Array
(
    [0] => g
    [1] => i
)

Для print_r(findPathBetweenNodes('a', 'c', $nodes));

Array
(
    [0] => b
    [1] => d
)

Будете ли вы писать какой-нибудь код для исправления структуры ввода?

mickmackusa 08.04.2024 23:50

@mickmackusa Мне не нравится код, но, похоже, он работает, насколько я все равно проверял. Не стесняйтесь переписать его.

Simon Goater 08.04.2024 23:52

Спасибо, Саймон, но я предпочитаю не изменять (расширять) переменную $nodes.

XTRUST.ORG 09.04.2024 01:13
Ответ принят как подходящий

Я согласен с Саймоном, ваша структура взаимоотношений узлов не идеальна для этой задачи. Значения, разделенные пробелами, требуют ненужной дополнительной работы и не могут быть оптимизированы для повышения производительности поиска. Вместо этого я рекомендую создать двухмерный массив поиска, поскольку PHP очень быстро ищет ключи (а не поиск значений).

В свою рекурсивную функцию я включил возможность избежать потенциальной циклической/бесконечной рекурсии путем удаления/потребления элементов из массива поиска при каждом более глубоком обходе.

Мой фрагмент не предназначен и не протестирован для работы в сценарии, в котором могут возникнуть несколько путей к узлам. Если это возможно, укажите это в тексте вопроса и предоставьте более сложные образцы данных (или задайте новый вопрос).

Чтобы отличить полные/успешные пути от несвязанных узлов, я разработал свою функцию так, чтобы она возвращала null, чтобы указать отсутствие подходящего пути.

Код: (Демо)

function findWayPoints(array $lookup, $start, $end, array $path = []): ?array
{
    if (isset($lookup[$start][$end])) {
        return $path;  // full path found; no need to further recurse
    }
    foreach ($lookup[$start] ?? [] as $conn => $irrelevant) {
        $result = findWayPoints(
            array_diff_key($lookup, [$start => null]),  // eliminate circular/infinite recursion
            $conn,  // change starting node in next call
            $end,
            array_merge($path, [$conn])  // append current match to path
        );
        if ($result !== null) {
            return $result;
        }
    }
    return null;  // dead end; kill path
}

function buildLookup($nodes) {
    $lookup = [];
    foreach ($nodes as $k => [$connections]) {
        foreach (explode(' ', $connections) as $conn) {
            $lookup[$k][$conn] = true;
            $lookup[$conn][$k] = true;
        }
    }
    return $lookup;    
}

$nodes = [
    'f' => ['d g'],
    'b' => ['a d'],
    'g' => ['i'],
    'd' => ['c e'],
    'i' => ['h']
];
$lookup = buildLookup($nodes);

   
echo json_encode(findWayPoints($lookup, 'h', 'f'));
echo "\n---\n";
echo json_encode(findWayPoints($lookup, 'f', 'h'));
echo "\n---\n";
echo json_encode(findWayPoints($lookup, 'a', 'c'));
echo "\n---\n";
echo json_encode(findWayPoints($lookup, 'a', 'b'));
echo "\n---\n";
echo json_encode(findWayPoints($lookup, 'a', 'h'));
echo "\n---\n";
echo json_encode(findWayPoints($lookup, 'i', 'j'));

Выход:

["i","g"]
---
["g","i"]
---
["b","d"]
---
[]
---
["b","d","f","g","i"]
---
null

Спасибо за решение. Как изменить его, чтобы найти все возможные маршруты?

XTRUST.ORG 10.04.2024 21:10

Теперь, когда на этот вопрос получен ответ, будет хорошей идеей не перемещать стойки ворот. Я рекомендую задать новый вопрос, сослаться на эту страницу как на недостаточно сложный минимальный воспроизводимый пример, затем показать свой новый MCVE и объяснить, в чем заключается ваша новая задача.

mickmackusa 11.04.2024 02:57

Другие вопросы по теме