[英]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.