如何在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一样。
答案 0 :(得分:0)
在这里发现问题。问题与我在尝试解决此问题时如何处理传递引用有关。
以下是解决方案:
$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 []运算符更快并且使用该函数
pop,因为它的返回是我之前推送的内容的副本,而不是我推送的实际元素。
此外,所有变量赋值必须通过引用(使用&amp;字符)显式地进行,因此使用current()进行赋值是不可能的,而是我需要像我一样使用key()函数。
我还有一个小而重要的错误,迫使我改变“while”指令。它现在包含current()而不是next()。这只是因为在堆栈弹出后我不能移动到下一个元素。在转到下一个之前,我需要再做一次迭代。这解决了当多个标签在同一个地方关闭时生成的错误嵌套。
请注意,此代码未针对速度进行优化。