【问题标题】:Scala - Use DFS for detecting a cycle? My code is buggy, and I can't seem to figure out whyScala - 使用 DFS 检测循环?我的代码有问题,我似乎无法弄清楚为什么
【发布时间】:2016-11-08 23:06:03
【问题描述】:

我正在尝试编写一个函数,如果图形有一个循环则返回 true,但我非常挣扎。我在 Scala 中表示一个图,如下所示,其中每个子列表的索引代表一个节点 0、1、2 向前,并且该子列表的组件表示从子列表索引到节点 2 的边,成本为 1例子。请注意,这是一个无向图表示。下面是一个有环的无向图示例。

ListBuffer(
  ListBuffer((1, 1), (2, 1), (3, 1)),
  ListBuffer((0, 1), (2, 2), (3, 2)),
  ListBuffer((0, 1), (1, 2)),
  ListBuffer((0, 1), (1, 2)))
)

这是我的代码,但它不起作用,我似乎无法弄清楚原因。

def hasCycle(graph: ListBuffer[ListBuffer[(Int, Int)]]): Boolean = {
  var visited: HashSet[Int] = HashSet()
  var lst: ListBuffer[Int] = ListBuffer()
  for (node <- graph.indices) {
    if (visited.contains(node)) {
      true
    } else {
      visited += node
      for (item <- getChildren(graph, node)) {
        visited += item
        lst += item
      }
      for (i <- lst) {
        visit(graph, i, node)
        lst = ListBuffer()
      }
    }
  }
  def visit(g: ListBuffer[ListBuffer[(Int, Int)]], node: Int, parent: Int): Unit = {
    for (child <- getChildren(g, node)) {
      if (visited.contains(child) && (child != parent)) {
          true
      } else if (!visited.contains(child) && (child != parent)) {
        visit(g, child, child)
      }
    }
  }
  false
 }
 /* Return the adjacent nodes to parent in graph */
 def getChildren(graph:  ListBuffer[ListBuffer[(Int, Int)]], parent: Int): ListBuffer[Int] = {
    var parentToChildren: Map[Int, ListBuffer[Int]] = Map()
    var childrenOfI: ListBuffer[Int] = ListBuffer()
    for (i <- graph.indices) {
      for (j <- graph(i)) {
        childrenOfI += j._1
      }
      parentToChildren += (i -> childrenOfI)
      childrenOfI = ListBuffer()
    }
    parentToChildren(parent)
  }

【问题讨论】:

  • 你应该在问题中添加代码(而不是描述它):你尝试过什么,什么不起作用,你想改进/使更多地道。

标签: scala list search graph cycle


【解决方案1】:

这是一种方法(诚然没有经过严格测试,所以请告诉我!),次优但确实包含一些 Scala 习语(在集合上使用 find、Set、不可变列表...):

type Graph = List[List[(Int, Int)]]

val g: Graph = List(
  List((1, 1), (2, 1)),
  ...
  )

def hasCycle(g: Graph): Boolean = {
  (0 to g.length - 1).find { source => //-- is there a cycle starting at this node?
    pathTo(source, source, (0 to source).toSet)
  }.isDefined
}

def pathTo(source: Int, destination: Int, visited: Set[Int]): Boolean = {
  //-- Is there a path from source to destination excluding visited?
  g(source).find { node => //-- find first case where
    node._1 == destination || ( //-- we've reached destination, or ...
      //-- we're allowed to continue (not yet visited), and there's a path this way
      !visited.contains(node._1) && pathTo(node._1, destination, visited + node._1))
  }.isDefined
}

顺便说一句,如果你还没有看过它们,你可能也对How do I check if a Graph is Acyclic的答案感兴趣

【讨论】:

  • 我不认为这是一个正确的解决方案,考虑var j : Graph = ListBuffer(ListBuffer((1,1),(2,1),(3,1)),ListBuffer((0,1)),ListBuffer((0,1)),ListBuffer((0,1))) 这是一个没有循环的图,但提供的代码返回true。
  • 您的节点 0 的边缘为 1(第一个元素),那么您的节点 1 的边缘为 0 (ListBuffer((0,1))...我误解了吗?
  • 是的,你理解正确。我正在处理无向图。
  • 我肯定遗漏了一些东西......我知道你的图表看起来像一朵花,中间有节点 0 和 3 个花瓣。从 0 到每个花瓣点 1、2、3 的边和从花瓣点到 0 的边。所以有 3 个循环 0-1-0、0-2-0 和 0-3-0。还是不行?
  • 从花瓣点到0的边是同一条边。你应该有一个只有三个边的图,这三个边是从节点 0 到每个节点 1、2、3。你能看到为什么这个图中没有循环吗?
猜你喜欢
  • 2021-04-26
  • 1970-01-01
  • 2013-11-21
  • 2012-03-15
  • 1970-01-01
  • 2018-01-15
  • 1970-01-01
相关资源
最近更新 更多