【问题标题】:Counting layers in tree like structure在树状结构中计算层数
【发布时间】:2016-09-17 13:27:42
【问题描述】:

我有一个使用 Map 的树状结构:

val m = Map[Int, (Set[Int], Set[Int])]()

其中节点id由id表示,每个集合分别是节点的父节点和子节点。我正在尝试递归计算节点上方和下方的层数。例如,我有像 (0 - 1 - 2 - (3,4)) 这样的树,并且我期待某个函数将结果作为集合列表返回,其中每个集合都是树的层。我有以下方法来收集所有父母

def p(n:Set[Int]):Set[Int] = if(n.isEmpty) Set.empty else n ++ m(n.head)._1 ++ p(n.tail)

但我希望它按树的相应级别分组,以便我可以通过调用它的 size 来获得所需的结果。

更新:

m = Map(0 -> (Set(), Set(1), 1 -> (Set(0), Set(2,3)), 2 -> (Set(1), Set(4,5), 3 -> (Set(2), Set(6,7) ....)

这是我的地图 m 在填满树节点后的样子,我想从中获取另一个地图,看起来像:

Map(0 -> (List(Set()), List(Set(1), Set(2,3), Set(4,5,6,7)), 1 -> (List(Set(), Set(0)), List(Set(2,3), Set(4,5,6,7)) ... and so on)

那是我想把它按每个级别分组,所有父层都在集合中,所有子层都在集合中。

下面是简化的例子:

val m = Map(2 -> (Set(1),Set(3, 4)), 4 -> (Set(2),Set()), 1 -> (Set(0),Set(2)), 3 -> (Set(2),Set()), 0 -> (Set(),Set(1)))

这里是如下结构的树 0 - 1 - 2 - 3, 4

所以这里的 0 是它的根,它有一个子节点,子节点 2 有 2 个子节点 3 和 4。在更复杂的情况下,节点可能有多个父节点,但它们都是唯一的,这就是我选择 set 的原因,尽管它可以是其他任何东西,但是使用 set 我可以轻松地向上收集所有父节点和向下收集所有子节点,我唯一想让它们按所在级别分组。在这种情况下,节点 3 应该有 List(Set(2), Set(1), Set(0), Set()) 作为其父节点。

【问题讨论】:

  • 您能否通过提供m 的文字说明以及您期望的输出来使这个示例更具体?
  • 当然,我更新了我的问题。
  • 谢谢。然而,Nether 示例实际上可以编译(我认为括号不匹配)。此外,它指定 2 和 3 是 1 的子级,但 2 是 3 的父级,那么它应该是这样的吗?此外,是否有理由将父级表示为一个集合?一个节点可以有多个父节点吗?

标签: scala tree


【解决方案1】:

BFS 类型的遍历

进行BFS 类型的遍历并继续将nodes 添加到map 以正确级别

BFS 保留一个队列(在此代码中使用List 作为队列)并逐级访问树/图。这就是我们需要的。

需要注意的重要一点是如何keep track of end of the level。我使用EndOfLevel 跟踪关卡结束

当您找到EndOfLevel 时,如果队列中还有剩余元素,则添加另一个EndOfLevel,如果不是说我们完成并返回结果。

sealed trait Node

  case class ANode(value: Int) extends Node

  case object EndOfLevel extends Node


  def bfs(root: Node, map: Map[Node, (Set[Node], Set[Node])]): List[(Int, Set[Node])] = {

     @tailrec
    def helper(queue: List[Node], level: Int, result: Map[Int, Set[Node]]): List[(Int, Set[Node])] = {

      if (queue.nonEmpty) {

        queue.head match {
          case anode@ANode(_) =>

            val newQueue = queue.tail ++ getNodes(anode, map)

            val newResult: Map[Int, Set[Node]] =
              if (result contains level) {
                result + (level -> (Set(anode) ++ result(level)))
              } else {
                result + (level -> Set(anode))
              }

            helper(newQueue, level, newResult)

          case EndOfLevel =>

            if (queue.tail.nonEmpty) helper(queue.tail ++ List(EndOfLevel), level + 1, result) else result

        }
      } else result
    }

    helper(List(root) ++ List(EndOfLevel), 0, Map(0 -> Set.empty[Node])).toList

  }

  def getNodes(node: Node, map: Map[Node, (Set[Node], Set[Node])]): Set[Node] = {
    val (left, right) = map.getOrElse(node, (Set.empty[Node], Set.empty[Node]))
    left ++ right
  }

请注意,您可以使用 Vector 而不是 List 使您的代码更优化。Vector appendList 更高效

运行代码

sealed trait Node

case class ANode(value: Int) extends Node

case object EndOfLevel extends Node

object Main {

  def bfs(root: Node, map: Map[Node, (Set[Node], Set[Node])]): List[(Int, Set[Node])] = {
    def helper(queue: List[Node], level: Int, result: Map[Int, Set[Node]]): Map[Int, Set[Node]] = {
      if (queue.nonEmpty) {
        queue.head match {
          case anode@ANode(_) =>
            val newQueue = queue.tail ++ getNodes(anode, map)
            val newResult: Map[Int, Set[Node]] =
              if (result contains level) {
                result + (level -> (Set(anode) ++ result(level)))
              } else {
                result + (level -> Set(anode))
              }
            helper(newQueue, level, newResult)
          case EndOfLevel =>
            if (queue.tail.nonEmpty) helper(queue.tail ++ List(EndOfLevel), level + 1, result) else result
        }
      } else result
    }
    helper(List(root) ++ List(EndOfLevel), 0, Map(0 -> Set.empty[Node])).toList
  }


  def main(args: Array[String]): Unit = {
    val map: Map[Node, (Set[Node], Set[Node])] = Map(
      ANode(1) -> (Set[Node](ANode(2)) -> Set[Node](ANode(3))),
      ANode(2) -> (Set[Node](ANode(4)) -> Set[Node](ANode(5))),
      ANode(3) -> (Set[Node](ANode(6)) -> Set[Node](ANode(7)))
    )
    println(bfs(ANode(1), map))

  }


  def getNodes(node: Node, map: Map[Node, (Set[Node], Set[Node])]): Set[Node] = {
    val (left, right) = map.getOrElse(node, (Set.empty[Node], Set.empty[Node]))
    left ++ right
  }
}

输出

List((0,Set(ANode(1))), (1,Set(ANode(3), ANode(2))), (2,Set(ANode(7), ANode(6), ANode(5), ANode(4))))

【讨论】:

  • 感谢您的回复,但在我的 5 个节点的树上,它进入了无限循环。这就是我为它填充数据的方式var m = Map.empty[t.Node, (Set[t.Node], Set[t.Node])] for(i <- 1 to 4){ m += t.ANode(i) -> (Set(t.ANode(i-1)), Set(t.ANode(i+1))) }
  • @Dmitrii 让我检查一下
  • @Dmitrii 代码有效。看起来您在编辑之前已经复制了代码。 ...我也粘贴了运行代码及其输出。希望这能给你一个清晰的想法。万事如意!!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-11
  • 1970-01-01
  • 2016-09-13
  • 2015-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多