从边缘组装有向根树而不爆炸内存?

时间:2018-01-06 00:27:17

标签: scala data-structures tail-recursion

给定一个边列表(parent< - > child),如何在递归数据结构中组装隐含的有向根树(任何子节点为1父节点,任何父节点无限制子节点){{1没有冒简单递归带来的堆栈溢出错误的风险?

Scala的奖金:

class Node(name: String, children: Array[Node])

1 个答案:

答案 0 :(得分:1)

我几乎不了解Scala,但这是一个非常与语言无关的问题。

首先,除非每个节点只有一个孩子,否则您的parentToChild数据结构没有意义。不太可能。您可能需要MultiMap

该算法非常简单:首先通过parentToChild多重映射只是为了构建一个新映射Name -> Node,其中所有节点中的子节点列表都是空的。然后再次通过parentToChild并使用新地图添加子指针。

我无法理解为什么你会认为递归会起作用。这是一个简单的迭代。

这里的伪代码:

set nameToNode = \empty
for each entry (parentName, childName) in parentToChild
  nameToNode.addIfNotPresent(parentName, new Node(parentName))
  nameToNode.addIfNotPresent(childName, new Node(childName))

for each entry (parentName, childName) in parentToChild
  set parent = nameToNode.get(parentName)
  set child = nameToNode.get(childName)
  parent.chilren.add(child)

如果您还不知道根节点,请添加以下内容:

set roots = \empty
set nodeToHasInwardEdge = \empty
for each entry (name, node) in nameToNode // name is ignored
  for each child in node.children
    nodeToHasInwardEdge.put(child, true)
for each entry (name, node) in nameToNode // name is ignored
  if nodeToHasInwardEdge.get(node) == null
    roots.add(node)

实际上,您可以将上面的第一个循环与前一个代码段中的第二个循环合并,因此只需要3遍就可以添加所有边并查找所有根。即使您认为您知道根,但最好将其用作检查。只需验证一个根目录。类似地,如果输入应该表示树,则可以使用整数计数而不是上面的布尔值,并验证每个非根节点只有一个入边。