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

深度优先(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.mfbz.cn/a/576390.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python基础之元组、集合和函数的定义与返回值

1.元祖 1.元祖的定义 元组的数据结构跟列表相似 特征&#xff1a;有序、 有序&#xff1a;有&#xff08;索引/下标/index&#xff09; 正序、反序标识符&#xff1a; ( ) 里面的元素是用英文格式的逗号分割开来关键字&#xff1a;tuple 列表和元组有什么区别&#xff1f; 元组…

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

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

局部多项式近似与 AMPM 算法

kappa3; %已在您的代码中定义% 定义窗口大小 windowSize (2*kappa1);% 初始化梯度估计值 [rows, cols] size(wrappedPhase); phi_y zeros(rows, cols); phi_x zeros(rows, cols);% 遍历每个窗口 for m 1kappa:rows-kappafor n 1kappa:cols-kappa% 提取局部窗口Z_mn wrap…

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

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

SHViT:具有内存高效宏设计的单头视觉Transformer

文章目录 摘要1、引言2、分析与方法2.1、宏观设计中的冗余分析2.2、微观设计中的冗余分析2.3、单头自注意力2.4、单头视觉转换器 3、实验3.1、实现细节3.2、SHViT在ImageNet-1K分类任务上的表现3.3、SHViT在下游任务中的表现3.4、消融研究 4、相关工作5、结论SHViT&#xff1a;…

python-opencv实现最近邻插值和双线性插值对图片上采样

使用背景 当我们需要把图像进行放大或者缩小的时候&#xff0c;第一反应是使用resize()实现。很多情况下&#xff0c;我们会调用最近邻插值和双线性插值去放大图片&#xff0c;当然要说没有分辨率的损失那是不可能的&#xff0c;只能说在放大图片的过程中尽可能增加了图片的分…

免费的一键伪原创工具,用来高效写文章真妙!

写文章是一件耗时间、费精力的事&#xff0c;遇到没有写作灵感的时候&#xff0c;写文章就像嚼蜡一样难受&#xff0c;但好在有免费的一键伪原创工具&#xff0c;它能帮助我们高效率实现自动写作文章&#xff0c;并且整个写作的过程我们无需思考内容怎么去写&#xff0c;是可以…

自动驾驶传感器篇: GNSSIMU组合导航

自动驾驶传感器篇&#xff1a; GNSS&IMU组合导航 1.GNSS1.1 GNSS 系统概述1.2 GNSS系统基本组成1. 空间部分&#xff08;Space Segment&#xff09;&#xff1a;2. 地面控制部分&#xff08;Ground Control Segment&#xff09;&#xff1a;3. 用户设备部分&#xff08;Use…

x86 64位的ubuntu环境下汇编(无优化)及函数调用栈的详解

1. 引言 为了深入理解c&#xff0c;决定学习一些简单的汇编语言。使用ubuntu系统下g很容易将一个c的文件编译成汇编语言。本文使用此方法&#xff0c;对一个简单的c文件编译成汇编语言进行理解。 2.示例 文件名&#xff1a;reorder_demo.cpp #include<stdio.h>typede…

摩尔定律仍在延续|从最新1.6nm工艺节点看芯片发展-2

2nm工艺的斗争还没结束&#xff0c;TSMC台积电就又公开宣布了1.6nm&#xff08;TSMC A16TM&#xff09;半导体工艺&#xff0c;太卷了&#xff01; TSMC A16TM技术采用领先的纳米片晶体管&#xff0c;并结合创新的背侧电源轨方案&#xff0c;计划于2026年投入生产。这种设计极…

【项目】YOLOv8/YOLOv5/YOLOv9半监督ssod火灾烟雾检测(YOLOv8_ssod)

假期闲来无事找到一份火灾烟雾数据集&#xff0c;自己又补充标注了一些&#xff0c;通过论文检索发现现在的火灾检测工作主要局限于对新场景的泛化性不够强&#xff0c;所以想着用半监督&#xff0c;扩充数据集的方法解决这个问题&#xff0c;所以本文结合使用现在检测精度较高…

成功案例丨守“鲜”有道 Fortinet为都乐筑就全球安全防护网

作为全球知名的跨国食品企业&#xff0c;都乐业务遍布各大洲。在各种新兴业务模式层出不穷的数字化时代&#xff0c;都乐面临着生产持续性、安全运营、供应链安全等严峻的网络安全挑战。通过采用Fortinet的FortiSIEM、FortiMail等系列Fortinet Security Fabric安全平台生态产品…

DaVinci Resolve Studio 19(达芬奇19调色剪辑)win/mac激活版

DaVinci Resolve Studio是一个结合专业的8k 编辑&#xff0c;颜色混合&#xff0c;视觉效果和音频后期制作的软件。只需点击一下&#xff0c;你就可以立即在编辑、混音、特效和音频流之间切换。此外&#xff0c;达芬奇解决(达芬奇)是一个多用户协作的解决方案&#xff0c;使编辑…

Swift - 基础语法

文章目录 Swift - 基础语法1. 常量1.1 只能赋值1次1.2 它的值不要求在编译时期确定&#xff0c;但使用之前必须赋值1次1.3 常量、变量在初始化之前&#xff0c;都不能使用 2. 标识符3. 常用数据类型4. 字面量4.1 布尔4.2 字符串4.3 整数4.4 浮点数4.5 数组4.6 字典 5. 类型转换…

OpenHarmony音视频—opus

简介 Opus是一种用于在互联网上进行交互式语音和音频传输的编解码器。它可以从低比特率窄带语音扩展到非常高的高品质立体声音乐。 下载安装 直接在OpenHarmony-SIG仓中搜索opus并下载。 使用说明 以OpenHarmony 3.1 Beta的rk3568版本为例 将下载的opus库代码存在以下路径&a…

OSPF的LSA详解

一、什么是LSA&#xff1f;LSA作用&#xff1f; 在OSPF协议中&#xff0c;LSA全称链路状态通告&#xff0c;主要由LSA头部信息&#xff08;LSA摘要&#xff09;和链路状态组成。部分LSA只有LSA头部信息&#xff0c;无链路状态信息。使用LSA来传递路由信息和拓扑信息&#xff0c…

2024全网最火的接口自动化测试,一看就会

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

网工内推 | 外企网工,思科认证优先,弹性工作,补贴多

01 淳华科技&#xff08;昆山&#xff09;有限公司 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1.全厂网络规划 2.Cisco交换机和路由器的配置 3.日常设备点检\维护\配置 4.网络设备的评估并做报告说明 任职要求&#xff1a; 1.具有一定的网络工作经验有Cisco或是其…

DNS域名系统 | unbound

目录 DNS 命名空间和域名结构 DNS的命名空间的结构: 域名服务器的分类&#xff1a; ​编辑 DNS 资源记录 常见type: DNS报文结构 请求报文&#xff1a; 响应报文&#xff1a; 解析类型 递归查询 迭代查询 DNS劫持 DNS劫持方法&#xff1a; 防御措施 DNS服务部署…

05_Scala运算符

文章目录 **1.Scala运算符****2.scala中没有 --等语法****3.逻辑运算符和Java完全相同****4.scala认为万物皆对象** 1.Scala运算符 Scala底层 使用的是equals() 程序员比较两个量的时候&#xff0c;谁来没事比较内存地址&#xff1f; Java中引用数据类型比较地址&#xff0…