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

news2024/10/6 8:27:32

深度优先(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.coloradmin.cn/o/1626329.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络安全实训Day17and18

写在前面 第17和18天都讲的sql注入&#xff0c;故合并 ​​​​​​ 网络空间安全实训-渗透测试 Web渗透 定义 针对Web站点的渗透攻击&#xff0c;以获取网站控制权限为目的 Web渗透的特点 Web技术学习门槛低&#xff0c;更容易实现 Web的普及性决定了Web渗透更容易找到目…

JavaEE 初阶篇-深入了解 I/O 高级流(缓冲流、交换流、数据流和序列化流)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 缓冲流概述 1.1 缓冲流的工作原理 1.2 使用缓冲流的步骤 1.3 字节缓冲流于字符缓冲流的区别 1.4 字节缓冲流的实例 1.5 字符缓冲流的实例 2.0 转换流概述 2.1 字符…

MySQL函数之单行函数

1.前言 我们在使用 SQL 语言的时候&#xff0c;不是直接和这门语言打交道&#xff0c;而是通过它使用不同的数据库软件&#xff0c;即DBMS。DBMS 之间的差异性很大&#xff0c;远大于同一个语言不同版本之间的差异。实际上&#xff0c;只有很少的函数是被 DBMS 同时支持的。比…

MySQL基础知识——MySQL索引

深入浅出索引 索引的意义 索引的意义&#xff1a;在大量数据中&#xff0c;加速访问少量特定数据&#xff1b; 使用索引的前提条件&#xff1a; 1&#xff09;索引块数量小于数据块数量&#xff1b; 2&#xff09;索引键有序&#xff0c;故可以使用二分查找等高效的查找方式&…

go语言并发实战——日志收集系统(十) 重构tailfile模块实现同时监控多个日志文件

前言 在上一篇文章中&#xff0c;我们实现了通过etcd来同时指定多个不同的有关分区与日志文件的路径&#xff0c;但是锁着一次读取配置的增多&#xff0c;不可避免的出现了一个问题&#xff1a;我们如何来监控多个日志文件&#xff0c;这样原来的tailFile模块相对于当下场景就…

前端到全栈进阶之“前端框架”

从前端入门到全栈-系列介绍 你会学到什么&#xff1f; 可能学不到什么东西&#xff0c;该系列是作者本人工作和学习积累&#xff0c;用于复习 系列介绍 现在的 Web 前端已经离不开 Node.js&#xff0c;我们广泛使用的 Babel、Webpack、工程化都是基于 Node 的&#xff0c;各…

【Linux】驱动_2_字符驱动

1. Linux设备分类 字符设备: 指应用程序按字节/字符来读写数据的设备。通常为传真、虚拟终端和串口调制解调器、键盘之类设备提供流通信服务&#xff0c;通常不支持随机存取数据。字符设备在实现时大多不使用缓存器。系统直接从设备读/写每一个字符。块设备: 通常支持随机存取…

【程序分享1】LAMMPS + OVITO + 晶体缺陷识别 + 点缺陷 + 分子动力学模拟

分享2个分子动力学模拟相关的程序。 1. 一种识别体心立方晶体缺陷的新方法。 2. 无后处理的分子动力学模拟中的并行点缺陷识别: lammps的计算和转储方式 。 感谢论文的原作者&#xff01; 第1个程序 关键词&#xff1a; 1. Atomistic simulations, 2. Molecular dynamics…

让客服工作开挂的8个客服办公高效率神器

做客服工作&#xff0c;经常需要写文案&#xff0c;做图片做视频&#xff0c;还要能快捷回复客户&#xff0c;都需要有靠谱的客服办公软件支持&#xff0c;本文介绍了8个高效神器&#xff0c;希望能帮到做客服的亲 前言 做客服工作&#xff0c;在回答客户咨询的同时&#xff0…

2024.4.28 机器学习周报

目录 引言 Abstract 文献阅读 1、题目 2、引言 3、创新点 4、总体流程 5、网络结构 5.1、损失函数 5.2、Confidence Maps 5.3、Part Affinity Fields(PAFs) 5.4、多人的PAFs 6、实验 7、结论 深度学习 yolov8实现目标检测和人体姿态估计 Yolov8网络结构 yaml…

【亲测可用】配置镜像源

文章目录 配置镜像源1. 手动添加镜像源2. 永久配置&#xff08;推荐&#xff09;方法1&#xff1a;方法2 &#xff1a; 小结 配置镜像源 配置镜像源会让资源下载的更快一些 我实验了一下&#xff0c;都成功了的方法&#xff0c;推荐给你们 1.手动添加 2.永久配置 前提是你的…

好看到爆炸的弹窗公告源码

源码介绍 好看到爆炸的弹窗公告源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面&#xff0c; 源码截图 源码下载 好看到爆炸的弹窗公告源码

新标准日本语初下 课后练习作业

新版标准日本语初下 第二十五課 これは明日会議で使う資料です 第二十五課 これは明日会議で使う資料です &#xff12;&#xff14;&#xff0d;&#xff10;&#xff14;&#xff0d;&#xff12;&#xff16; 練習&#xff12;&#xff15;&#xff0d;1&#xff0d;1 例…

Vuforia AR篇(四)— AR虚拟按钮

目录 前言一、创建虚拟按钮二、创建脚本三、效果 前言 在当今互联网和移动设备普及的背景下&#xff0c;**增强现实&#xff08;AR&#xff09;**技术正迅速成为连接现实世界与数字信息的重要桥梁。AR虚拟按钮作为这一技术的创新应用&#xff0c;不仅提供了一种全新的用户交互…

[极客大挑战 2019]Upload、[ACTF2020 新生赛]Upload、[MRCTF2020]你传你呢

[极客大挑战 2019]Upload 打开环境&#xff0c;是上传一句话木马的题 先上传1.php试试&#xff0c;发现不可以 试试改后缀为phtml&#xff0c;提示语句中不能包含<?&#xff0c;只能改木马&#xff1a; <script language"php">eval($_POST[line]);</sc…

ListView、RecycleView、动画、单位、ViewPager

ListView列表 老版本 public View oldGetView(int position, View convertView, ViewGroup parent) {//返回每一个item//拿到布局if (convertViewnull)convertView LayoutInflater.from(context).inflate(R.layout.my_list_view, parent, false);//find会耗时需要优化TextVi…

YOLOv8核心原理深度解析

YOLOv8源码地址: https://github.com/ultralytics/ultralytics 一、简介: 根据官方描述,Yolov8是一个SOTA模型,它建立在Yolo系列历史版本的基础上,并引入了新的功能和改进点,以进一步提升性能和灵活性,使其成为实现目标检测、图像分割、姿态估计等任务的最佳选择。其具体…

Rancher-Longhorn-新增磁盘以及卷创建原理和卷副本调度规则

一、添加磁盘-官网指引 重点在于&#xff1a; 1、比如你新增了一块盘&#xff0c;你需要做一下事情&#xff1a; 1、执行 lsblk 能找到你的盘。 2、然后执行 fdisk /dev/sdxx 分区你的盘。 3、然后对于分区部署文件系统&#xff0c; mkfs.xfs 4、然后执行 mount /dev/sdxxx 你…

项目管理中常用的三个工具:甘特图、看板、燃尽图

在日常项目管理的实践中&#xff0c;为了更有效地追踪项目进度、优化资源配置和提高团队协作效率&#xff0c;管理者常常会借助一些工具来辅助工作。这些工具的本质在于将抽象复杂的项目管理任务具象化、简单化&#xff0c;以更直观、方便的方式呈现出来。 以下介绍项目管理中…

Git--基础学习--面向企业--持续更新

一、基础学习 1.1基本命令 //查询基础信息 git config --global --list //选取合适位置创建 mkdir 文件名 //创建文件夹 //全局配置 git config --global user.email "****e***i" git config --global user.name "*** K****"//--------------------进入…