【算法基础实验】图论-深度优先搜索和深度优先路径

深度优先(DFS)

理论基础

深度优先搜索(DFS, Depth-First Search)是图和树的遍历算法中的一种,它从一个节点开始,沿着树的边走到尽可能深的分支,直到节点没有子节点为止,然后回溯继续搜索下一个分支。DFS 是一种使用递归或栈实现的算法,它深入到每一个分支直到无路可走再退回到上一个分岔点,这种方式有助于解决许多搜索和路径问题。

DFS 的基本步骤

  1. 标记和访问:从一个未访问的节点开始,标记它为已访问。
  2. 递归探索:对于当前节点的每一个未访问的相邻节点,继续执行深度优先搜索(递归调用DFS)。
  3. 回溯:当一个节点的所有相邻节点都被访问后,回溯到之前的节点继续探索未访问的节点。

DFS 的特点

  • 深度优先:它尝试尽可能深地搜索图的分支。
  • 使用栈:无论是显式使用栈还是通过递归调用的隐式栈,DFS 都利用栈先进后出的特性来管理节点和回溯。
  • 可能非最短路径:DFS 不保证找到的是最短路径,它可能在找到目标前遍历图中大部分节点。
  • 解空间树:在涉及路径和状态的问题中,DFS 常用于生成解空间树,并通过回溯剪枝。
  • 复杂性:在最坏的情况下,DFS 的时间复杂度是 O(V+E),其中 V 是顶点数,E 是边数。

DFS 的应用场景

  • 路径搜索:在迷宫或图中查找从起点到终点的路径。
  • 拓扑排序:在有向无环图中进行拓扑排序。
  • 连通分量:在无向图中查找所有连通分量。
  • 解决问题:如解决迷宫问题、路径问题和那些可以通过回溯方法解决的问题。

简单总结

深度优先搜索是一个递归的过程,它尝试深入到每一个分支直到不能再深入为止,然后通过回溯继续探索其他分支。它的核心在于尝试所有可能的路径直到找到解决方案或覆盖所有的节点。DFS 的记忆点在于它的递归性质和回溯机制,这使得它非常适合处理需要探索所有可能性的问题。

前提

JAVA实验环境

实现Bag抽象数据结构

实现Stack抽象数据结构

实现无向图的构建

数据结构

本算发中涉及到的基本数据结构

private boolean[] marked
private int[] edgeTo
private final int s
myLinkedStack //一种栈的实现,具体见以下链接
myGraph //一种无向图的实现

myGraph的数据结构图

请添加图片描述

实验数据和实验环境

本实验要求根据DFS算法实现从任意一点的深度优先路径的打印功能

实验数据是一个名为tinyCG.txt的文件,用来构建如下图所示的无向图

请添加图片描述

算法流程

请添加图片描述

根据以上深度优先搜索得到的结果,整理输出从起点到图中所有点的

下图为从0到5的深度优先路劲的计算过程,我们可以计算出从任意起点到其他所有点的深度优先路径

请添加图片描述

代码实现

import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;public class myDepthFirstPaths {private boolean[] marked;private int[] edgeTo;private final int s;public myDepthFirstPaths(myGraph G, int s){this.s = s;marked = new boolean[G.V()];edgeTo = new int[G.V()];dfs(G, s);}private void dfs(myGraph G, int v){marked[v] = true;for(int w:G.adj(v))if(!marked[w]){edgeTo[w]=v;dfs(G,w);}}public boolean hasPathTo(int v){return marked[v];}public Iterable<Integer> pathTo(int v){if(!hasPathTo(v)) return null;myLinkedStack<Integer> path = new myLinkedStack<Integer>();for(int x=v;x!=s;x=edgeTo[x]) path.push(x);path.push(s);return path;}public static void main(String[] args){myGraph G = new myGraph(new In(args[0]));int s = Integer.parseInt(args[1]);myDepthFirstPaths search = new myDepthFirstPaths(G,s);for(int v=0; v < G.V(); v++){StdOut.print(s+" to "+v+":");if(search.hasPathTo(v)){for(int x:search.pathTo(v))if(x==s) StdOut.print(x);else StdOut.print("-"+x);StdOut.println();}}}
}

代码详解

这段代码实现了一个用于无向图的深度优先搜索(DFS)路径查找类 myDepthFirstPaths。它可以找到从一个给定的起始顶点 s 到图中任意其他顶点的路径。以下是代码的详细解读和功能介绍:

类定义与变量


public class myDepthFirstPaths {private boolean[] marked;  // 用于标记每个顶点是否已被访问private int[] edgeTo;      // 从起点到一个顶点的已知路径上的最后一个顶点private final int s;       // 起始顶点
  • marked[] 数组用于跟踪每个顶点是否被访问过。
  • edgeTo[] 数组记录到达每个顶点的最后一步的前一个顶点。
  • s 是算法开始的起点。

构造函数


public myDepthFirstPaths(myGraph G, int s){this.s = s;marked = new boolean[G.V()];edgeTo = new int[G.V()];dfs(G, s);
}

构造函数初始化 markededgeTo 数组,并从顶点 s 开始对图 G 进行深度优先搜索。

深度优先搜索方法


private void dfs(myGraph G, int v){marked[v] = true;for(int w: G.adj(v))if(!marked[w]){edgeTo[w] = v;dfs(G, w);}
}

这是一个递归方法,它标记顶点 v 为已访问,然后对于每个与 v 相邻的未访问顶点 w,记录 w 是从 v 达到的,并递归地继续深度优先搜索。

路径检查与生成


public boolean hasPathTo(int v){return marked[v];
}public Iterable<Integer> pathTo(int v){if (!hasPathTo(v)) return null;myLinkedStack<Integer> path = new myLinkedStack<Integer>();for (int x = v; x != s; x = edgeTo[x])path.push(x);path.push(s);return path;
}
  • hasPathTo 方法检查是否存在从起点 s 到顶点 v 的路径。
  • pathTo 方法返回从起点 s 到顶点 v 的路径,使用一个自定义的栈 myLinkedStack 来逆序存储路径。

主方法


public static void main(String[] args){myGraph G = new myGraph(new In(args[0]));int s = Integer.parseInt(args[1]);myDepthFirstPaths search = new myDepthFirstPaths(G, s);for (int v = 0; v < G.V(); v++){StdOut.print(s + " to " + v + ":");if (search.hasPathTo(v)){for (int x : search.pathTo(v))if (x == s) StdOut.print(x);else StdOut.print("-" + x);}StdOut.println();}
}

主方法从文件中读取图,并从指定的起点 s 开始搜索。对于图中的每个顶点 v,如果存在从 sv 的路径,则打印该路径。

这个程序展示了如何使用深度优先搜索来找出图中从一个特定起点到所有其他顶点的路径。这些路径可以用于多种应用,比如网络路由、社交网络中的连接查找等。

实验

编译代码

javac myDepthFirstPaths.java

运行代码

代码运行要输入两个参数,首先是用于构造无向图的tinyCG.txt文件,第二个是起点的数值

最终的打印结果是从0分别到1,2,3,4,5的深度优先路径

java myDepthFirstPaths tinyCG.txt 0 
0 to 0:0
0 to 1:0-2-1
0 to 2:0-2
0 to 3:0-2-3
0 to 4:0-2-3-4
0 to 5:0-2-3-5

参考资料

算法(第4版)人民邮电出版社

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/650991.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

超全面的软件测试面试题

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 测试技术面试题 1、什么是兼容性测试&#xff1f;兼容性测试侧…

公众号偷偷“干大事”,公众号“留言”功能已可直接开通

在微信公众号的运营过程中&#xff0c;许多运营者都面临着一个令人头疼的问题&#xff0c;那就是自2018年以后注册的微信公众号无法再自带留言功能。这一变化是根据微信官方的通知而实施的。具体来说&#xff0c;自2018年2月12日起&#xff0c;微信对新注册的公众号进行了调整&…

白平衡简介

文章目录 白平衡的概念白平衡的调节常见的白平衡模式 白平衡的概念 白平衡是指摄影、摄像和显示技术中的一项重要概念&#xff0c;用于调节图像中的白色或中性灰色的色彩&#xff0c;使其看起来在不同光源条件下都是准确的白色或灰色。白平衡的主要目的是确保图像的色彩准确性…

OSPF域间路由防环原则

1.域间路由防环原则 ①原则一 1&#xff09;为了避免区域间的环路&#xff0c;OSPF规定不同区域间的路由交互只能通过ABR实现。 2&#xff09;ABR是连接到骨干区域的&#xff0c;所以在区域设计上规定&#xff0c;所有非骨干区域都要连接到骨干区域。区 域间的通讯需要通…

公钥密码学Public-Key Cryptography

公钥或非对称密码学的发展是整个密码学历史上最伟大的&#xff0c;也许是唯一真正的革命。The development of public-key, or asymmetric, cryptography is the greatest and perhaps the only true revolution in the entire history of cryptography. 公钥算法基于数学函数…

visual studio python输出中文乱码问题

之前在网上搜了一大堆教程花费了我半天时间&#xff0c;发现都没解决我的问题 最终问了好几次gtp才解决了问题 所以制作了这期教程以防自己搞忘 1.首先先看问题我们这里输出“你好世界会直接出现乱码问题” 这是因为我们这里高级保存选项没有用UTF-8编码&#xff0c;把它改…

关于pdf.js中文本坐标尺寸的使用

一个电子教材项目中有这样一个需求&#xff1a; 用户向网站上传一个PDF书籍后&#xff0c;网站可以对PDF书籍进行解析&#xff0c;并支持用户对PDF书籍的每一页做一些操作&#xff0c;比如&#xff1a;为英语课本的单词和句子添加音频热区。因为热区数量很多&#xff0c;所以&a…

【算法】人工蜂群算法,解决多目标车间调度问题,柔性车间调度问题

文章目录 复现论文什么是柔性作业车间调度问题&#xff1f;数据处理ABC算法编码解码种群初始化雇佣蜂操作IPOX交叉多点交叉 观察蜂操作侦察蜂操作算法流程 结果程序截图问询、帮助 复现论文 什么是柔性作业车间调度问题&#xff1f; 也叫多目标车间调度问题。 柔性作业车间调…

Java中的ArrayList

ArrayList<E>的特点 可调整大小的数组实现 <E>:是一种数据类型 ArrayList的构造方法 ArrayList list new ArrayList();创建一个空的集合对象 package dayhou40.day45; ​ import java.util.ArrayList; ​ public class Arraylisttest {public static void ma…

设置Linux开发板开机自启动QT程序的报错解决办法

设置Linux开发板开机自启动QT程序报错解决办法 设置开发板开机自启动QT 打开 /etc/init.d/rsC 文件&#xff0c;添加以下内容 cd / ./my_start_run.shmy_start_run.sh 是自己编写的自启动脚本&#xff0c;内容例如下&#xff1a;(也可以将这些直接写到 /etc/init.d/rsC 文件…

STM32应用开发教程进阶--UART串口重定向(printf)

实现目标 1、掌握STM32 HAL库的串口重定向 2、具体目标&#xff1a;1、实现printf “打印”各种常用的类型的数据变量 一、串口“打印” UART串口通信协议是我们常用的通信协议&#xff08;UART、I2C、SPI等&#xff09;之一&#xff0c;全称叫做通用异步收发传输器&#xf…

ROS_第一个程序_Hello_world

ROS的第一个项目&#xff1a;输出Hello World 我们将学习如何创建一个简单的ROS&#xff08;Robot Operating System&#xff09;项目&#xff0c;该项目将在终端中输出"Hello World"。我们将使用Python语言进行编程。 环境准备 首先&#xff0c;确保你的计算机已…