2016-08-16 31 views
2

更新:PHP遞歸的foreach意外行爲

我想通了什麼導致無限循環,放在一個檢查,以確保每個節點只在路徑中包含一次。這現在返回一個具有期望值的多級數組。關於如何在單級數組中獲得這一切的任何想法?

Array 
(
    [0] => Array 
     (
      [0] => 200 
      [1] => Array 
       (
        [0] => Array 
         (
          [0] => 109 
         ) 

        [1] => 155 
       ) 

      [2] => Array 
       (
        [0] => Array 
         (
          [0] => 164 
         ) 

        [1] => 110 
       ) 

     ) 

) 

新代碼:

function buildPath($nodes,$src,$target,$pathSum,$elements=array(1)) 
     { 
      $paths=array(); 
      foreach($nodes[$src] as $dest=>$dist) 
      { 
       $e=$elements; 
       $sum=$pathSum+$dist; 
       if(!in_array($dest,$e)) 
       {     
        if($dest==$target) 
        { 
         $paths[]=$sum; 
        } 
        else 
        { 
         $e[]=$dest; 
         $paths[]=buildPath($nodes,$dest,$target,$sum,$e); 
        } 
       } 
      } 
      return $paths; 
     } 

原貼

長時間的潛伏者,首次海報。我會認爲自己在PHP中處於中級水平,並且我開始深入到遞歸函數中。我遇到了一些意想不到的行爲,我很困惑。

function buildPath($nodes,$src,$target,$pathSum) 
    { 
     $paths=array(); 
     foreach($nodes[$src] as $dest=>$dist) 
     { 
      $sum=$pathSum+$dist; 
      if($dest==$target) 
      { 
       $paths[]=$sum; 
      } 
      elseif($dest!=$target) 
      { 
       $paths[]=buildPath($nodes,$dest,$target,$sum); 
      } 
     } 
     return $paths; 
    } 

當我調用函數:

$src=1 
$target=4 
$pathSum=0 
$nodes= Array 
(
    [1] => Array 
     (
      [4] => 200 
      [2] => 5 
      [3] => 10 
     ) 

    [4] => Array 
     (
      [1] => 200 
      [2] => 150 
      [3] => 100 
     ) 

    [2] => Array 
     (
      [1] => 5 
      [3] => 4 
      [4] => 150 
     ) 

    [3] => Array 
     (
      [1] => 10 
      [2] => 4 
      [4] => 100 
     ) 

) 

它運行一個無限循環直到超時。我開始在不同的時間迴應變量來嘗試和調試。當我打電話:

function buildPath($nodes,$src,$target,$pathSum) 
     { 
      $paths=array(); 
      foreach($nodes[$src] as $dest=>$dist) 
      { 
       $sum=$pathSum+$dist; 
       if($dest==$target) 
       { 
        $paths[]=$sum; 
        echo "$src->$dest, Target=$target, distance=$dist, sum=$sum. | "; 
       } 
       elseif($dest!=$target) 
       { 
        $paths[]=buildPath($nodes,$dest,$target,$sum); 
        echo "$src->$dest, elseif clause | "; 
       } 
      } 
      print_r($paths); 
      return $paths; 
     } 

用相同的投入,我得到下面的輸出:

1->4, Target=4, distance=200, sum=200. | 1->4, Target=4, distance=200, sum=210. | 1->4, Target=4, distance=200, sum=220. | 1->4, Target=4, distance=200, sum=230. | 1->4, Target=4, distance=2, sum=240. | 1->4, Target=4, distance=200, sum=250. | 

反覆進行,直到腳本超時,由10每次迭代增量總和。轉儲$路徑顯示它不會將任何內容追加到$ paths數組,只需將$ paths [0]更新爲新的和。

我在這裏錯過了什麼?我完全誤解遞歸應該如何工作?

+0

'$ n' From? – Poiz

+0

'$ paths [] = buildPath($ nodes,$ dest,$ n,$ sum);'** $ n如何被神奇地邀請參加聚會?** – Poiz

+0

對不起,用$ target取代$ n。我試圖澄清代碼,並且必須在完成所有替換之前進行復制。我的代碼調用$ paths [] = buildPath($ nodes,$ dest,$ target,$ sum) – Amanda

回答

2

只要把$paths的功能之外,在函數中使用它作爲一個全局變量如下圖所示,你可以測試一下out here

<?php 

     $src  = 1; 
     $target  = 4; 
     $pathSum = 0; 
     $nodes  = [ 
      1=>[4=>200, 2=>5, 3=>10], 
      4=>[1=>200, 2=>150, 3=>100], 
      2=>[1=>5,  3=>4, 4=>150], 
      3=>[1=>10,  2=>4, 4=>100], 
     ]; 

     $paths = array(); //<== OUTSIDE THE FUNCTION.... AS GLOBAL VARIABLE... 

     var_dump(buildPath($nodes, $src, $target, $pathSum)); 

     function buildPath($nodes, $src, $target, $pathSum, $elements=array(1)) { 
      global $paths; 
      foreach($nodes[$src] as $dest=>$dist){ 
       $e  = $elements; 
       $sum = $pathSum+$dist; 

       if(!in_array($dest, $e)) { 
        if($dest == $target){ 
         $paths[] = $sum; 
        }else{ 
         // SIMPLY RECURSE & NOT BUILD $path HERE 
         $e[] = $dest; 
         buildPath($nodes, $dest, $target, $sum, $e); 
        } 
       } 
      } 
      return $paths; 
     } 

     // THE var_dump ABOVE PRODUCES:::   
     array (size=5) 
      0 => int 200 
      1 => int 109 
      2 => int 155 
      3 => int 164 
      4 => int 110 
+0

太棒了,這個作品,謝謝!因爲它的工作原因,標記爲答案,並且是優雅的。我設法以另一種方式解決它,而不是使$ path成爲全局的,在我的「else」塊中,我使用了'$ paths = array_merge($ paths,buildPath($ nodes,$ dest,$ target,$ sum,$ e) ;' – Amanda

1

能否請您更改,並檢查從

elseif($dest!=$target) 
     { 
      $paths[]=buildPath($nodes,$dest,$n,$sum); 
     } 

elseif($dest<=$target) 
     { 
      $paths[]=buildPath($nodes,$dest,$n,$sum); 
     } 
+0

這不是無限循環,但不是我想要的。那原本是一個else子句,但在故障排除時我將其更改爲else。仍然看到意想不到的結果。它只更新$ paths [0]而不是將另一個元素附加到數組。 – Amanda

2

Managed t o像這樣解決:

function buildPath($nodes,$src,$target,$pathSum,$elements=array(1)) 
     { 
      $paths=array(); 
      foreach($nodes[$src] as $dest=>$dist) 
      { 
       $e=$elements; 
       $sum=$pathSum+$dist; 
       if(!in_array($dest,$e)) 
       {     
        if($dest==$target) 
        { 
         $paths[]=$sum; 
        } 
        else 
        { 
         $e[]=$dest; 
         $paths=array_merge($paths,buildPath($nodes,$dest,$target,$sum,$e)); 
        } 
       } 
      } 
      return $paths; 
     }