递归树遍历 - 如何跟踪递归级别?

时间:2011-10-26 08:06:46

标签: php recursion

我基本上是尝试从表示树结构的多维数组构建一个html ul / li嵌套列表。

以下代码工作正常,但我想改进它:

我需要一种方法来跟踪递归级别,这样我就可以将不同的类应用到不同的级别,为生成的输出添加缩进等。

function buildTree($tree_array, $display_field, $children_field, $class='', $id='') {

  echo "<ul>\n";

  foreach ($tree_array as $row) {

    echo "<li>\n";
    echo $row[$display_field] . "\n";

    if (isset($row[$children_field])) {

      $this->buildTree($row[$children_field]);
    }
    echo "</li>\n";
  }
  echo "</ul>\n";
} 

$ tree_array如下所示:

Array
(
    [0] => Array
        (
            [category_id] => 1
            [category_name] => calculatoare
            [parent_id] => 0
            [children] => Array
                (
                    [0] => Array
                        (
                            [category_id] => 4
                            [category_name] => placi de baza
                            [parent_id] => 1
                        )

                    [1] => Array
                        (
                            [category_id] => 5
                            [category_name] => carcase
                            [parent_id] => 1
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [category_id] => 6
                                            [category_name] => midi-tower
                                            [parent_id] => 5
                                        )

                                )

                        )

                )

        )

    [1] => Array
        (
            [category_id] => 2
            [category_name] => electronice
            [parent_id] => 0
        )

    [2] => Array
        (
            [category_id] => 3
            [category_name] => carti
            [parent_id] => 0
        )

)

我已将此标记为家庭作业,因为我希望将此作为一个机会来改善我对递归的理解(差),所以,我会感谢能够指导我解决问题的答案,而不是提供完整的答案。工作实例:))

3 个答案:

答案 0 :(得分:8)

Quick'n'dirty方法(请参阅下面的“扰流器”块):

在函数声明中添加一个额外的变量$recursionDepth,默认为0。

在每次后续递归中,使用$recursionDepth + 1调用您的函数。

由于函数变量对于函数的相应实例仅是“可见的”(作用域),因此最终会得到当前迭代深度的指示符。

此外,您的功能第12行

$this->buildTree();

并不认为它会起作用 - 原因是你没有将变量传递给下一个buildTree实例。

它可能应该是这样的:

$this->buildTree($row[$children_field], $display_field, $children_field, $class, $id)

以下是我为您的代码所做的更改,以实现您的目标:

function buildTree($tree_array, $display_field, $children_field, $class='', $id='', $recursionDepth = 0, $maxDepth = false)
{
    if ($maxDepth && ($recursionDepth == $maxDepth)) return;

    echo "<ul>\n";

    foreach ($tree_array as $row)
    {
        echo "<li>\n";
        echo $row[$display_field] . "\n";

        if (isset($row[$children_field]))
            $this->buildTree($row[$children_field], $display_field, $children_field, $class, $id, $recursionDepth + 1, $maxDepth);

        echo "</li>\n";
    }
    echo "</ul>\n";
}

答案 1 :(得分:7)

你正在使你的生活变得比它需要的更困难。为方便起见,SPL提供了多个iterators。使用RecursiveArrayIterator class可以轻松遍历多维数组。它不仅允许您处理任何级别深度数组,而且还可以跟踪深度。

实施例

$iterator = new RecursiveIteratorIterator(
    new RecursiveArrayIterator($array)
);

for($iterator; $iterator->valid(); $iterator->next())
{
    printf(
        "Key: %s Value: %s Depth: %s\n",
        $iterator->key(),
        $iterator->current(),
        $iterator->getDepth()
    );
}

Example on codepad

正如您所看到的,有一个方法getDepth()将始终告诉您当前的迭代深度。这是在递归迭代器中迭代子节点所需的RecursiveIteratorIterator方法。

如果您需要影响迭代开始时或访问子项时发生的事情,请查看我对Multidimensional array iteration的回答,该回答显示了将多维数组的值包装成自定义RecursiveIteratorIterator的自定义{{1}} xml元素并按当前迭代的深度缩进它们(这对于适应ul / li元素应该是微不足道的。)

另请参阅Wikipedia Article about Iterators进行一般性介绍。

答案 2 :(得分:-1)

public virtual int GetLevelById(int id)
        {
            int i = GetParentById(id);
            if (i == 0)
                return 1;
            else
                return (1 + GetLevelById(i));
        }

public virtual int GetParentById(int t)         {             var ret = this._list.FirstOrDefault((f)=&gt; f.Id == t);             if(ret!= null)                 return ret.ParentId;             返回-1;         }