簡體   English   中英

通過在PHP中遍歷數組來構建樹

[英]Building a tree from transversing an array in PHP

如何通過PHP中的數組來構建樹,知道構建樹需要遵循的規則?

我在代碼中沒有什么地方可以找到真正的錯誤
無論如何,問題可能與我反復使用的引用傳遞有關。
我沒有使用遞歸,因為速度在這里真的重要。 根據輸入數組具有的規則(我可以完全控制它們),這是可能的,而且速度更快,而無需遞歸。

工作原理:橫切數組時,每個元素的['start_order']比前面的['start_order']更大。
每當下一個元素的['start_order']大於此元素的['start_order']且下一個元素的['end_order']小於此元素的['end_order']時,則該元素是該元素的子元素
在這一步之后,我必須找到該元素的所有子元素(我剛剛發現它是該元素的子元素的孩子)。

這是我的代碼。

<?php
ksort($treeArray);
$tree = array();
$stack = array();
reset($treeArray);
$currentParent = &$treeArray[key($treeArray)];
$tree[] = &$treeArray[key($treeArray)];

while(next($treeArray) !== false){

    if(current($treeArray)['start_order'] <= $currentParent['end_order']){
        if(current($treeArray)['end_order'] <= $currentParent['end_order']){
            // There's a child of the previous

            // push the new parent
            $stack[] = $currentParent;

            if(!isset($currentParent['children'])){
                $currentParent['children'] = array();
            }
            $currentParent['children'][] = &$treeArray[key($treeArray)];
            $currentParent = current($treeArray);

        }else{
            // Supposed not to happen. Log the problem.
        }
    }else /* if(current($treeArray)['start_order'] > $currentParent['end_order']) */{
        // Pop the child here, there are no more children.
        if(($popedElement = array_pop($stack)) === NULL){
            $tree[] = $currentParent;
        }else{
            $popedElement['children'][] = &$treeArray[key($treeArray)];
            $stack[] = $popedElement;
            $currentParent = current($treeArray);
        }
    }
}

?>

例:

該輸入數組的結構可以如下所示:

[1][child1][child1child1][child2][child2child1][child2child2][child2child3][2][child2child1]

解析為該樹:

[1]
    [child1]
        [child1child1]
    [child2]
        [child2child1]
        [child2child2]
        [child2child3]
[2]
    [child2child1]

並且不要忘了這個順序得以維持。 [child2child3]永遠不會出現在[child2child2]之前,[2]永遠不會出現在[1]之前。 以此類推,幾乎就像處理XML時一樣。

在這里找到問題。 問題與嘗試解決此問題時如何處理傳遞引用有關。

解決方法如下:

$tree[] = &$treeArray[key($treeArray)];
$currentParent = &$treeArray[key($treeArray)];
next($treeArray);

while(current($treeArray) !== false){

    if(current($treeArray)['start_order']['start_position'] <= $currentParent['end_order']['end_order']){
        if(current($treeArray)['end_order']['end_order'] <= $currentParent['end_order']['end_order']){
            // There's a child of the previous

            // push the new parent
            $stack[] = &$currentParent;

            $currentParent['children'][] = &$treeArray[key($treeArray)];

            $currentParent = &$treeArray[key($treeArray)];
        }else{
            // Supposed not to happen. Log the problem.
        }
        next($treeArray);
    }else /* if(current($treeArray)['start_order']['start_position'] > $currentParent['end_order']['end_order']) */{
        // Close previous element here. There are no more children.

        if(end($stack) === false){
            $currentParent = &$treeArray[key($treeArray)];
            $tree[] = &$treeArray[key($treeArray)];

            next($treeArray);
        }else{              
            $currentParent = &$stack[key($stack)];
            unset($stack[key($stack)]);
        }
    }
}

主要問題實際上是傳遞引用,這在PHP中與在C中不同。
為了解決這個問題,我無法同時使用push或pop php函數:
推送是因為$ var []運算符更快並且使用了該函數。
流行音樂,因為它的返回是我之前推送的內容的副本,而不是我實際推送的元素。

另外,必須通過引用(使用&字符)顯式地進行所有變量賦值,因此使用current()進行賦值是不可能的,相反,我需要像以前一樣使用key()函數。

我還有一個小而重要的錯誤,迫使我更改了“ while”指令。 現在它包含current()而不是next()。 這只是因為在彈出堆棧之后,我不能移動到下一個元素。 在移至下一個之前,我需要進行另一次迭代。 這解決了當多個標簽在同一位置關閉時產生的不良嵌套。

請注意,此代碼並未針對速度進行優化

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM