У меня есть график:
Вот данные:
$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)); Возвращает пустой массив.
Как исправить функцию, чтобы она работала и в других случаях? Спасибо.
Является ли этот граф направленным или неориентированным? В вашей диаграмме используются стрелки, но ваш «правильный» пример проходит обратный путь между «начальным» и «конечным» узлами.
@Sammith - Направление графика не имеет значения.
Вы не использовали слово «правильный» для описания двух вторых тестовых случаев; так можем ли мы предположить, что эти результаты неверны? Хотите a, чтобы c вернуться ['b', 'd']? Я считаю, что ваше объяснение и требования неясны. Что означает How to fix a function to make it work in other cases too?? Пожалуйста, предоставьте больше тестовых примеров и желаемый результат для каждого (покажите достаточно сложные случаи, чтобы исключить двусмысленность).
Я думаю, что есть причина для беспокойства по поводу желаемого вывода, потому что, когда два входных узла напрямую соединены, желаемым результатом является пустой массив (в пути не требуются дополнительные соединения), И когда два входных узла не имеют соединения, желаемый результат результат — пустой массив. Эти неоднозначные результаты не кажутся пригодными для использования в реальном приложении.
Отвечает ли это на ваш вопрос? Поиск путей в неориентированном графе
Я рассмотрел рекомендуемую цель для обмана. Он связан с темой, но имеет большую сложность данных, стремится подсчитать потенциально несколько удовлетворяющих путей и больше заинтересован в советах по алгоритму, чем в реальном закодированном решении. По этим причинам я не буду поддерживать закрытие этой обманной цели.






Массив $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 Мне не нравится код, но, похоже, он работает, насколько я все равно проверял. Не стесняйтесь переписать его.
Спасибо, Саймон, но я предпочитаю не изменять (расширять) переменную $nodes.
Я согласен с Саймоном, ваша структура взаимоотношений узлов не идеальна для этой задачи. Значения, разделенные пробелами, требуют ненужной дополнительной работы и не могут быть оптимизированы для повышения производительности поиска. Вместо этого я рекомендую создать двухмерный массив поиска, поскольку 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
Спасибо за решение. Как изменить его, чтобы найти все возможные маршруты?
Теперь, когда на этот вопрос получен ответ, будет хорошей идеей не перемещать стойки ворот. Я рекомендую задать новый вопрос, сослаться на эту страницу как на недостаточно сложный минимальный воспроизводимый пример, затем показать свой новый MCVE и объяснить, в чем заключается ваша новая задача.
Ради здравомыслия людей, читающих ваш код, не определяйте именованные функции внутри других функций.