使用三色算法进行循环检测与使用一套 - 使用其中一种优于另一种的任何优势?

时间:2018-05-28 06:54:24

标签: algorithm graph depth-first-search

这两种看似相似的方法可以检测图表中的循环:

  1. 遍历图表,DFS样式,假设所有节点都是白色的,直到您第一次访问它们,使它们变为灰色。在节点上完成所有处理后,将其变为黑色。如果您访问过灰色节点,则表示您有一个循环。

  2. 遍历图形,DFS样式,并保留一个集合S,其中包含当前DFS堆栈中的所有节点(仅用于性能目的)。每次访问节点时,都会将其添加到S,每次完成节点后,都会将其从S中删除。如果在任何时候您尝试访问已在S中的节点,则存在循环。

  3. 选择其中一种替代方案是否有任何实际优势?我可能会失去一些权衡吗?或者使用一个或另一个导致完全相同?

    由于

1 个答案:

答案 0 :(得分:3)

这两个在概念上是等价的:集合S恰好包含灰色节点,否则算法是相同的。

然而,在实践中,存在细微差别:

  • 如果set S是基于散列的实现,则节点必须是可散列的。如果散列函数的设计很差,或者数据是对抗性的,那么性能就会受到影响。
  • 如果集合S是基于树的实现,则节点必须具有可比性。此外,您不再具有(分期)常量时间设置查找。
  • 如果使用颜色,则节点必须具有未用于其他目的的“颜色”字段。但是,这提供了最快的“设置查找”,因为它只是一次查找/比较。
  • 如果图表是定向或断开的,那么您将需要多次DFS(来自所有白色节点)。跟踪节点是否已被访问需要第二组,因为第一组在DFS结束时始终为空。因为实际上有3个节点“状态”,所以需要2组来存储该信息。

在性能关键的情况下,颜色方法将具有较小的线性运行时常数因子。但是,如果向节点添加color字段不是一个选项,那么使用集合是一个很好的选择。如果节点当前实现为intString s(而不是Node类,可以添加字段),那么设置方法将更容易编码,因为您可以避免改变节点的表示。