【问题标题】:PHP Find path in multidimensional arrayPHP在多维数组中查找路径
【发布时间】:2018-08-26 08:06:16
【问题描述】:

假设我们有一个数组,其中包含许多定义特定节点路径的数组。例如:

X1     X3     X5     
|      |      |      
A  --  B  --  C  --  D
|      |      |      
X2     X4     X6     

还有代码:

$array = [
  'A' => ['B','X1','X2'],
  'B' => ['C','X3','X4'],
  'C' => ['D','X5','X6'],
];

用最多 2 个节点找到从一个点到另一个点的路径的最佳方法是什么?例如,要从 A 到 D,您需要从 A 到 B 到 C 再到 D。

现在我已经编写了一个执行此搜索的函数,但我确信有更好的方法来执行此搜索(可能是递归的)。

private function findpath($array, $start, $end)
{
    $result = array();

    foreach ($array[$start] as $key1 => $value1) {
        foreach ($array[$value1] as $key2 => $value2) {
                if (in_array($end, $array[$value2])) {
                    return $result = [$start, $value1, $value2, $end];
                }
        }
    }
} 

findpath($array, 'A', 'D');

// returns
// array:4 [
  // 0 => "A"
  // 1 => "B"
  // 2 => "C"
  // 3 => "D"
// ] 

【问题讨论】:

    标签: php path nodes


    【解决方案1】:

    一种可能的方法是使用堆栈作为要检查的路径列表。在一个循环中,您可以从堆栈中删除一条路径,检查它是否找到目标,如果没有,则通过在节点的$array 中查找下一步来生成新路径,然后将新路径添加到堆栈中由循环的下一次迭代检查。如果堆栈为空,则意味着找不到从开始到结束的路径。

    您提供的原始$array 不允许路径循环或重复,但出于测试目的,我扩展了您的数组,假设所有节点都完全连接:

    $array = [
        'A' => ['B','X1','X2'],
        'B' => ['A', 'C','X3','X4'],
        'C' => ['B', 'D','X5','X6'],
        'D' => ['C'],
        'X1' => ['A'],
        'X2' => ['A'],
        'X3' => ['B'],
        'X4' => ['B'],
        'X5' => ['C'],
        'X6' => ['C'],
    ];
    

    鉴于此,维护一个单独的已访问节点列表也是一个好主意,这样代码就不会重新访问节点或陷入循环路径。

    这个函数会找到两个节点之间的最短路径,或者返回false表示找不到路径(用php 5.6测试过):

    function findpath(array $array, $start, $end, $steps = null)
    {
        $visited = []; // keep track of nodes already visited to avoid loops
        $paths = [[$start]]; // array of paths to be checked
        while ($path = array_pop($paths)) {
            $node = end($path);
            if ($node === $end) {
                return $path; // found path from start to end node
            }
            if ($steps !== null && count($path) > $steps) {
                continue; // path too long
            }
            $visited[$node] = true;
            if (empty($array[$node])) {
                continue; // can't reach any other nodes from this path
            }
            foreach ($array[$node] as $next) {
                if (isset($visited[$next])) {
                    continue; // already visited next node
                }
                // make new path by adding next node to current path
                // then add new path to array of paths to be checked
                $paths[] = array_merge($path, [$next]);
            }
        }
        return false; // no paths left to check, cannot find path from start to end node
    }
    

    您可以选择为函数提供最大步数(例如路径 A -> B -> C -> D 为 3 步):

    var_dump(findPath($array, 'A', 'D', 3));
    // returns ['A', 'B', 'C', 'D']
    
    var_dump(findPath($array, 'A', 'D', 2));
    // returns false as path would be longer than 2 steps
    
    var_dump(findPath($array, 'X1', 'X6'));
    // returns ['X1', 'A', 'B', 'C', 'X6']
    

    【讨论】:

      猜你喜欢
      • 2011-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-11
      相关资源
      最近更新 更多