代码之家  ›  专栏  ›  技术社区  ›  devoured elysium

使用三色算法进行循环检测与使用集合相比-使用其中一个比另一个有什么优势?

  •  1
  • devoured elysium  · 技术社区  · 7 年前

    有两种看似相似的方法来检测图中的循环:

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

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

    在选择一个替代方案时,是否有任何实际优势?我可能会失去某种平衡?或者使用一个或另一个导联来完全相同?

    谢谢

    1 回复  |  直到 7 年前
        1
  •  3
  •   k_ssb    7 年前

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

    然而,在实践中,有一些细微的差别:

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

    在性能关键的情况下,颜色方法对于线性运行时具有较小的常量因子。但如果添加 color int String S(相对于A Node 通过添加字段的可能性来初始化),那么set方法将更易于编码,因为您可以避免更改节点的表示形式。