如何识别孤立的节点

时间:2010-06-04 14:22:30

标签: arrays sorting multidimensional-array hierarchical-data orphaned-objects

我有一个存储在DB中的节点层次结构。我选择all,将它们存储在一个数组中,然后迭代它们并在内存中创建一个嵌套数组。

输入如下:

  

[{name:A},{name:B},{name:X,parent:A},{name:Y,parent:A},{name:C}]

输出如下:

  

[{name:A,children:[{name:X},{name:Y}]},{B},{C}]

嵌套的深度没有限制。

我遇到的问题是,如果其中一条记录的父引用无效,则无法将其放入层次结构中,并且脚本以无限循环结束,尝试查找父级。

我打赌有一种方法可以告诉我什么时候陷入无限循环。对于记录,当在循环中我意识到没有父项将项目插入时,我将项目推送到数组的末尾,因为父项可能存在于该行中。

我想我应该能够意识到我一遍又一遍地骑着相同的物品?

编辑1 - 代码 这是重要的一点:

    $cnt = count($array);
    do {
        $item = array_shift($array);
        if ($this->push($item)) {
            $cnt--;
        } else {
            array_push($array, $item);
        }
    } while ($cnt > 0);

($ this-> push()是一种尝试查找父项的方法,如果成功,则将$ item插入其层次结构中)

1 个答案:

答案 0 :(得分:1)

看起来您正在使用队列(从前面删除,添加到后面)类型 用于存储未处理节点的数据结构。作为节点 插入到输出数据结构中,它们将从队列中删除。如果 节点无法添加到输出中(因为它的“父”没有 已被移动到输出数据结构) 它被重新排队。最终队列应该变空 除非存在“父”不存在的节点(孤儿)。

我想你的算法看起来像

 Do While not QueueEmpty()
    node = Dequeue() ' Remove from the front
    if not AddNodeToTree(node) then Queue(node) 'add to the back
 end

其中AddNodeToTree是成功获取节点的函数 将其添加到输出并返回True。否则返回False 导致节点回收。

您唯一需要做的就是将一个sentinal节点添加到队列的后面 和一个标志,指示队列中至少消耗了一个节点 在一个完整的循环中通过它。上述算法变为:

set NodeProcessed to False
Queue(SentinalNode) ' marker to identify cycle through queue
Do while not QueueEmpty()
  node = Dequeue()
  if isSentinalNode(node) then
     if NodeProcessed then 
        Queue(node)
        set NodeProcessed to False
     else
        ' Queue contains only orphans or is empty
     end
  end
  if AddNodeToTree(node) then
     set NodeProcessed to True
  else
     Queue(node)
  end
end

SentinalNode是用于检测循环的标记 通过队列。

您的输出数据结构看起来像包含树的“森林”。那是, 它包含几个不同的树。如果有可能的话 可以在两个或更多个树之间共享给定节点,如上所述 算法无法正常工作。如果节点最多可能出现 在“森林”中的一棵树,那么上面应该没问题。