使用堆栈的非递归深度优先搜索 (DFS)

2023-11-23

好吧,这是我在 Stack Overflow 上的第一篇文章,我已经阅读了一段时间并且非常欣赏这个网站。我希望这是可以接受的问题。所以我一直在阅读《算法简介》(Cormen. MIT Press),并且我已经了解了图形算法。我一直在非常详细地研究为广度和深度优先搜索而设计的正式算法。

这是深度优先搜索的伪代码:

DFS(G)
-----------------------------------------------------------------------------------
1  for each vertex u ∈ G.V
2      u.color ← WHITE       // paint all vertices white; undiscovered
3      u.π ← NIL
4      time ← 0              // global variable, timestamps
5  for each vertex u ∈ G.V
6      if u.color = WHITE
7          DFS-VISIT(G,u)

DFS-VISIT(G, u)
-----------------------------------------------------------------------------------
1  u.color ← GRAY          // grey u; it is discovered
2  time ← time + 1 
3  u.d ← time
4  for each v ∈ G.Adj[u]   // explore edge (u,v)
5      if v.color == WHITE
6          v.π ← u
7          DFS-VISIT(G,v) 
8  u.color ← BLACK         // blacken u; it is finished
9  time ← time + 1
10 u.f ← time

该算法是递归的,并且来自多个源(将发现未连接图中的每个顶点)。它具有大多数语言特定实现可能会忽略的几个属性。它区分顶点的 3 种不同“颜色”。它最初将它们全部漆成白色,然后当它们被“发现”(在 DFS-VISIT 中访问)时,它们就会被漆成灰色。 DFS-VISIT 算法运行一个循环,在当前顶点的邻接列表上递归地调用自身,并且仅当顶点没有到任何白色节点的边时才将其绘制为黑色。

此外,还维护每个顶点的另外两个属性 u.d 和 u.f 是发现顶点(涂成灰色)或完成顶点(涂成黑色)时的时间戳。第一次绘制节点时,它的时间戳为 1,并且每次绘制另一个节点时(无论是灰色还是黑色),它都会递增到下一个整数值。 u.π 也被维护,它只是一个指向发现 u 的节点的指针。

Algorithm Non-Recursive-DFS(G)
-----------------------------------------------------------------------------------
1   for each vertex u ∈ G.V
2       u.color ← WHITE
3       u.π ← NIL
4   time = 0
5   for each vertex u ∈ G.V
6       if u.color = WHITE
7           u.color ← GRAY
8           time ← time + 1
9           u.d ← time
7           push(u, S)
8           while stack S not empty
9               u ← pop(S)
10              for each vertex v ∈ G.Adj[u]
11                  if v.color = WHITE
12                      v.color = GRAY
13                      time ← time + 1
14                      v.d ← time
15                      v.π ← u
16                      push(v, S)
17              u.color ← BLACK 
18              time ← time + 1
19              u.f ← time

* 编辑 2012 年 10 月 31 日 *令人尴尬的是,我的算法长期以来一直不正确,它在大多数情况下都有效,但不是全部。我刚刚得到了这个问题的一个热门问题徽章,我看到 Irfy 在下面的答案中发现了问题所在,所以这就是功劳所在。我只是在这里为将来需要它的人修复它。

有人发现上述算法有缺陷吗?到目前为止,我不是图论方面的专家,但我认为我对递归和迭代有很好的掌握,并且我相信这应该是一样的。我希望使其在功能上等同于递归算法。它应该保留第一个算法的所有属性,即使它们不需要。

当我开始写它时,我并没有想到我会有一个三重循环,但结果就是这样。当我环顾 Google 时,我看到了其他迭代算法,它们只有双重嵌套循环,但是,它们似乎并不是从多个来源进行的。 (即他们不会发现未连接图的每个顶点)


两种算法都很好。第二个是从递归到基于堆栈的直接转换。所有变异状态都存储在堆栈中。G在算法执行过程中永远不会改变。

该算法将根据算法访问每个节点的顺序为每个断开连接的区域生成一棵生成树。树将通过对父节点的引用来表示(u.π),以及线段树(u.d and u.f).

子节点将拥有对其父节点的引用(或NULL如果它是根),以及它的范围(child.d .. child.f) 包含在其父级范围内。

parent.d < child.d < child.f < parent.f

child.π = parent

Edit:我发现翻译中有一个错误。您实际上并不是将当前状态推入堆栈,而是将未来的方法参数推入堆栈。此外,您没有为弹出的节点着色GRAY并设置f field.

这是最初的第一个算法的重写:

algorithm Stack-DFS(G)
    for each vertex u ∈ G.V
        u.color ← WHITE
        u.π ← NIL
    time ← 0
    S ← empty stack
    for each vertex u ∈ G.V
        if u.color = WHITE
            # Start of DFS-VISIT
            step ← 1
            index ← 0
            loop unconditionally
                if step = 1
                    # Before the loop
                    u.color ← GRAY
                    time ← time + 1
                    u.d ← time
                    step ← 2
                if step = 2
                    # Start/continue looping
                    for each vertex v ∈ G.Adj[u]
                        i ← index of v
                        if i ≥ index and v.color = WHITE
                            v.π ← u
                            # Push current state
                            push((u, 2, i + 1), S)
                            # Update variables for new call
                            u = v
                            step ← 1
                            index ← 0
                            # Make the call
                            jump to start of unconditional loop
                    # No more adjacent white nodes
                    step ← 3
                if step = 3
                    # After the loop
                    u.color ← BLACK
                    time ← time + 1
                    u.right ← time
                    # Return
                    if S is empty
                        break unconditional loop
                    else
                        u, step, index ← pop(S)

可能有一些地方可以优化,但至少现在应该可以工作。

Result:

Name   d    f   π
q      1   16   NULL
s      2    7   q
v      3    6   s
w      4    5   v
t      8   15   q
x      9   12   t
z     10   11   x
y     13   14   t
r     17   20   NULL
u     18   19   r
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用堆栈的非递归深度优先搜索 (DFS) 的相关文章

  • 有人可以解释以下异或属性

    我的一个论坛提到给定的数组n数字 arr 0 n 1 以下条件成立 is the xor运算符 f l r f 0 r f 0 l 1 where f l r arr l arr l 1 arr r 我检查了上面的数组数量和不同的值l an
  • Bokeh 中单独的节点和边缘悬停工具?

    我正在尝试为 Bokeh 中的节点和边缘获取单独的悬停工具提示 但未能使其正常工作 有人可以指出我做错了什么吗 我相信代码应该如下所示 from bokeh io import show output notebook from bokeh
  • 将字符串中的“奇怪”字符转换为罗马字符

    我需要能够将用户输入仅转换为 a z 罗马字符 不区分大小写 所以 我感兴趣的角色只有26个 然而 用户可以输入他们想要的任何 形式 的字符 西班牙语 n 法语 e 和德语 u 都可以包含用户输入中的重音符号 这些重音符号会被程序删除 我已
  • 如何仅使用单个数组在 JavaScript 中模拟调用堆栈

    我正在看维基百科页面 https en wikipedia org wiki Call stack在调用堆栈上 并尝试理解这个图像 据我所知 哈哈 const memory memory 0 3 top of stack pointer m
  • 异或交换可以扩展到两个以上的变量吗?

    我一直在尝试将异或交换扩展到两个以上的变量 例如n变量 但我没有得到比这更好的地方3 n 1 对于两个整型变量x1 and x2你可以像这样交换它们 swap x1 x2 x1 x1 x2 x2 x1 x2 x1 x1 x2 所以 假设你有
  • C# 中的 strstr() 等效项

    我有两个byte 我想找到第二个的第一次出现byte 在第一个byte 或其中的一个范围 我不想使用字符串来提高效率 翻译第一个byte to a string会效率低下 基本上我相信就是这样strstr 在 C 中做 最好的方法是什么 这
  • 如何有效地找到距给定点最远的点(从一组点中)?

    我正在寻找一种算法或数据结构来解决以下问题 给你一组点 S 然后你会得到另一个点形式的 Q 查询 对于每个查询 找到集合中距离给定点最远的点 集合中最多有 10 5 个点和 10 5 个查询 所有点的坐标都在 0 到 10 5 范围内 我想
  • 计算两点之间的最短路线

    过去几周我一直在开发一款多人 HTML5 游戏 使用nodejs and websockets 我已经被这个问题困扰了一段时间 想象一下 我用数组实现了这个平铺地图 如下所示 1 or 棕色瓷砖 路上有障碍物 玩家无法通过 0 or 绿色瓷
  • Florian 的 Grisu2 算法如何工作?

    我遇到了一个关于将 double 转换为 ascii 的问题 经过搜索 我得到了 Florian 的论文 使用整数快速准确地打印浮点数 http www cs tufts edu nr cs257 archive florian loits
  • 实施二分查找有哪些陷阱? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 二分查找比看起来更难实现 虽然二分搜索的基本思想相对简单 但细节可能出人意料地棘手 Donald Knuth 新的二分搜索实现中最有可
  • 举例解释bpe(字节对编码)?

    有人可以帮忙解释一下背后的基本概念吗BPE模型 除了这张纸 https arxiv org abs 1508 07909 目前还没有那么多解释 到目前为止我所知道的是 它通过将罕见和未知的单词编码为子词单元序列来实现开放词汇表上的 NMT
  • 用于开始和/或包含搜索的最快字符串集合结构/算法是什么

    我有以下情况 我有一个大的字符串集合 比如说 250 000 平均长度可能是 30 我要做的就是在这些搜索中进行许多搜索 大多数搜索都是 StartsWith 和 Contains 类型的 该集合在运行时是静态的 这意味着选择的集合的初始读
  • Java递归方法求阶乘返回负输出[重复]

    这个问题在这里已经有答案了 我知道这是溢出 但问题是 20 是相对较小的数字 这不应该发生 对吧 有没有更好的方法来查找大数 例如 1000 的阶乘 而不会得到这种奇怪的结果 public class RecursiveFunctionsE
  • Matlab:3D 堆积条形图

    我正在尝试创建一个 3D 堆积条形图 如这个问题所示 Matlab 中的 3D 堆叠条形图 https stackoverflow com questions 13156133 3d stacked bars in matlab 5D 然而
  • 每个术语出现的次数

    我得到了一个数组a n 2 where n can be 10 5最大时有n个科目和n个学生 全部编号为 1 2 n a i 0 and a i 1 1 lt i lt n 表示在第 i 个科目中 所有来自a i 0 to a i 1 通过
  • 照片马赛克算法。如何在给定基本图像和瓷砖列表的情况下创建马赛克照片?

    Hy 我要做的是创建一个程序 使用 C 或 C 它将 24 位 像素位图和图像集合作为输入 我必须创建一个马赛克图像 类似于使用库的输入图像给定的图像 创建与输入类似的马赛克照片 到目前为止 我可以访问输入的图像像素及其颜色 但我有点卡住了
  • 有没有时间复杂度为O(N)的排序算法?

    大多数排序算法的复杂度为 O NN 或 O NlogN 来实现结果 但是 对于特定的输入集 有些算法的复杂度为 O N 我想知道是否有一种排序算法在所有情况下都具有 O N 的复杂度 如果您只能比较 检查两个项目是否为 正在排序的值 那么您
  • 数学/算法使图像适合屏幕保留纵横比

    我需要数学 算法方面的帮助来拍摄已知尺寸的图像并适合两个屏幕尺寸之一 720 x 480 或 1280 x 1024 图像尺寸来自 XML 文件 但这些尺寸是 Web 尺寸 我还从 XML 中选择了一些图像 这些图像的分辨率可能比 Web
  • O(1) 算法确定节点是否是多路树中另一个节点的后代?

    想象一下下面的树 A B C D E F 我正在寻找一种方法来查询 F 是否是 A 的后代 注意 F 不需要是directA 的后代 在这种特殊情况下这是正确的 只需要针对更大的潜在后代节点池测试有限数量的潜在父节点 当测试一个节点是否是潜
  • 将名称字符串编码为唯一的数字

    我有一大堆名字 数以百万计 他们每个人都有一个名字 一个可选的中间名和一个姓氏 我需要将这些名称编码为唯一代表这些名称的数字 编码应该是一对一的 即一个名称只能与一个数字相关联 一个数字只能与一个名称相关联 对此进行编码的明智方法是什么 我

随机推荐

  • 方便地移动列

    关于如何将列移动到第一个或最后一个位置有很多很好的问题和答案 Using dplyr最佳答案分别类似于 iris2 lt iris gt head 2 iris2 gt select Sepal Width everything move
  • 在命名元组列表中建立索引并查找值

    我有一个如下所示的命名元组 tup myTuple a b c 其中 可以是任何值 字符串 数字 日期 时间等 现在 我列出了这些命名元组并想要找到 假设 c 1 以及 a 和 b 的相应值 有没有Pythonic的方法可以做到这一点 使用
  • 字体大小独立的 UI:当我切换到 120 DPI 时一切都崩溃了?

    因此 我正在阅读有人在另一个问题中链接到的 Windows Vista UI 指南 他们提到您应该能够在切换到 120 DPI 后继续生存 好吧 我启动了安装了应用程序的便捷虚拟机 然后我们得到了什么 啊啊啊 大规模用户界面失败 一切都杂乱
  • 将一个输入文件与给定数量的文件进行匹配的算法

    我上周去面试了 我被算法回合中的一个问题困住了 我回答了这个问题 但面试官似乎并不相信 这就是为什么我分享同样的内容 请告诉我这个问题有什么优化的方法 以便对我以后的面试有帮助 Question 给出了 20 个文本文件 所有文件都是 AS
  • 为什么局部变量的地址每次都会不同?

    我询问了 Google 并在 StackOverflow 上做了一些研究 我的问题是 当我进入main 在C 程序中调用函数并声明第一个变量 为什么该变量的地址在不同的执行过程中会有所不同 请参阅下面我的示例程序 include
  • Android - 显示动画状态栏图标

    我正在尝试将通知状态栏图标设置为动画 android R drawable stat sys upload 它工作正常 但图标没有动画 private void showStatusNotification NotificationMana
  • 使用 IF/ELSE IF 语句的奇怪错误

    我试图创建一个依赖于场景参数值的临时表并使用以下 IF 语句 但出现以下错误 IF indexName A begin select top 400 into temp from pretemp order by EMRev desc en
  • Android.mk 中的每个文件 CPPFLAGS

    我正在处理一个 Android mk 文件 其中对于单个模块 其中一个文件需要不同的 CPPFLAGS 也就是说 它需要启用 frtti 而其他则需要 Android 默认的 fno rtti 显而易见的解决方案是目标特定变量 但奇怪的是
  • Microsoft Chart堆积柱形图有间隙

    我正在使用 Net 4 0 中的图表库来创建包含多个系列的堆叠柱形图 我的目标是一个直方图 显示多个系列 教师 每天的累积操作数 报告完成情况 经常会丢失数据 特定教师当天没有活动 当系列中缺少数据时 我会在条形图中出现间隙 My code
  • jQuery ajax: 即使响应正常 200 也会运行错误

    我有一个通过 AJAX 使用 remote gt true 提交表单的表单 查看服务器日志和 FireBug 我得到响应 200 OK 它以以下形式返回 JSON email email protected 然后我有这两个处理程序 new
  • TypeError:不是函数打字稿类

    我在打字稿类中收到以下错误 并且无法理解原因 我所做的就是尝试调用传递令牌的辅助函数 Error 发布错误 TypeError this storeToken 不是函数 Class Authentication Service Contai
  • 按升序排序,但最后保留零

    假设我有一个矩阵A 在下面的表格中 A 35 1 6 3 32 0 0 9 0 0 0 0 我想按升序排序 但最后保留零 我知道我可以用所有零替换inf 排序 然后替换infs 再次为零 如中所提议的这个问题 我认为有一个更简单的方法 至少
  • StyleCop/FxCop 10 - 如何仅在命名空间级别正确抑制消息?

    FxCop 10 抱怨以下内容 using XYZ Blah CA1709 XYZ using Xyz Blah No complaint using XylophoneSuperDuperLongFullName Blah I don t
  • ABAP CDS 视图中的可选参数?

    我正在尝试创建一个 CDS 视图以供使用可选参数的使用 但目前不支持可选参数 是否有一种解决方法可以根据输入参数以某种方式选择要执行 使用哪些 where 子句 你检查了吗消耗 defaultValue注解 请看一下参考文件
  • 解析日期时间,时区格式为 PST/CEST/UTC/etc

    我正在尝试解析类似于以下内容的国际日期时间字符串 24 okt 08 21 09 06 CEST 到目前为止我已经得到了类似的东西 CultureInfo culture CultureInfo CreateSpecificCulture
  • jQuery DataTables - 通过精确匹配过滤列

    尝试仅显示与搜索栏中输入的搜索词完全匹配的内容 例如 我有一个按 ID 进行过滤的搜索栏 我只想显示与输入的确切 匹配的记录 So if 123已输入 我不想要12345 91239等要显示的内容 仅有的123 看到一些关于bRegex在常
  • 如何将 AES 初始化向量传递给混合密码系统的客户端

    我需要实现客户端 服务器通信的安全性 我已经实施了以下混合密码系统 为了在混合密码系统中加密发送给 Alice 的消息 Bob 执行以下操作 获取Alice的公钥 为数据封装方案生成新的对称密钥 使用刚刚生成的对称密钥在数据封装方案下加密消
  • Ajax Control Toolkit 加载了太多脚本资源

    我创建了一个新项目 我从 NuGet 安装了 Ajax Control Toolkit 然后我使用以下代码创建了一个新页面 aspx
  • 如何从多类分类的混淆矩阵中提取假阳性、假阴性

    我正在使用以下 Keras 代码对 mnist 数据进行分类 从confusion matrix的命令sklearn metrics我得到了混淆矩阵并且来自TruePositive sum numpy diag cm1 命令我能够得到真阳性
  • 使用堆栈的非递归深度优先搜索 (DFS)

    好吧 这是我在 Stack Overflow 上的第一篇文章 我已经阅读了一段时间并且非常欣赏这个网站 我希望这是可以接受的问题 所以我一直在阅读 算法简介 Cormen MIT Press 并且我已经了解了图形算法 我一直在非常详细地研究