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

深度优先(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.mzph.cn/diannao/5946.shtml

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

相关文章

ubuntu外置网卡配置AP模式

外置网卡RTL8811CU设置 UBUNTU使用RTL8811CU网卡&#xff08;包含树莓派&#xff09; 外置网卡配置AP模式流程 1. 检查网卡支持情况&#xff08;是否支持AP模式&#xff09; iw list找到以上部分&#xff0c;发现支持AP 2. 安装依赖 sudo apt-get update sudo apt-get in…

c语言从入门到函数速成(1)

温馨提醒&#xff1a;本篇文章适合人群&#xff1a;刚学c又感觉那个地方不怎么懂的同学以及以及学了一些因为自身原因停学一段时间后又继续学c的同学 好&#xff0c;正片开始。 主函数 学c时最先学的是我们c语言程序的主体函数&#xff0c;c的主函数有两种写法&#xff0c;这…

25 JavaScript学习:var let const

JavaScript全局变量 JavaScript中全局变量存在多种情况和定义方式&#xff0c;下面详细解释并提供相应的举例&#xff1a; 使用var关键字声明的全局变量&#xff1a; var globalVar "我是全局变量";未使用var关键字声明的变量会成为全局变量&#xff08;不推荐使用&…

【御控物联网平台】物联网数据传输数据格式

物联网平台常用设备消息的标准数据格式为JSON&#xff0c;但是不同厂家、不同型号设备数据传输格式各异&#xff0c;给物联网平台带来数据解析的压力。御控物联网平台提供支持JSON数据消息解析功能的代码库&#xff08;JS、Java、.Net&#xff09;&#xff0c;实现设备自定义JS…

八大排序详解:动图、代码、注释

目录 何为八大排序&#xff1f; 直接插入排序 排序过程解读 直接插入排序的特性总结&#xff1a; 希尔排序 希尔排序的特性总结&#xff1a; 直接选择排序 直接选择排序的特性总结&#xff1a; 堆排序 直接选择排序的特性总结&#xff1a; 冒泡排序 快速排序 1.Hoa…

初学React基础

最近准备跟着黑马React学一下React&#xff0c;扩充一下技术面&#xff0c;打算还是以一边学习一边记笔记为主&#xff0c;进行学习&#xff01; 1. React介绍 1.1. React是什么&#xff1f; React是由FaceBook现在称&#xff08;Meta&#xff09;开发的开源 JavaScript 库&a…

【leetcode】数组和相关题目总结

1. 两数之和 直接利用hashmap存储值和对于索引&#xff0c;利用target-nums[i]去哈希表里找对应数值。返回下标。 class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {unordered_map<int, int> mp;vector<int> res;fo…

【linux】进程间通信(匿名管道)

对于本篇文章我们采取三段论&#xff1a;是什么 为什么 怎么办。 目录 进程间为什么要通信&#xff1f;进程间如何通信&#xff1f;进程间怎么通信&#xff1f;匿名管道&#xff1a;匿名管道原理&#xff1a;代码示例&#xff1a;匿名管道的情况与特征&#xff1a; 进程间为什…

win下vscode的vim切换模式的中英文切换

问题描述 在vscode中安装vim插件后&#xff0c;如果insert模式下完成输入后&#xff0c;在中文输入方式下按esc会发生无效输入&#xff0c;需要手动切换到英文。 解决方法 下载完成vscode并在其中配置vim插件下载github—im-select.exe插件&#xff08;注意很多博文中的gitcod…

【MySQL篇】使用mysqldump全量+mysqlbinlog增量完成实例的全库恢复(第四篇,总共四篇)

☘️博主介绍☘️&#xff1a; ✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章&am…

每天五分钟深度学习框架pytorch:如何创建多维Tensor张量元素?

本文重点 上节课程我们学习了如何创建Tensor标量,我们使用torch.tensor。本节课程我们学习如何创建Tensor向量,我们即可以使用torch.Tensor又可以使用torch.tensor,下面我们看一下二者的共同点和不同点。 Tensor张量 tensor张量是一个多维数组,零维就是一个点(就是上一…

【数据结构】链表专题3

前言 本篇博客我们继续来讨论链表专题&#xff0c;今天的链表算法题是经典中的经典 &#x1f493; 个人主页&#xff1a;小张同学zkf ⏩ 文章专栏&#xff1a;数据结构 若有问题 评论区见&#x1f4dd; &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐文章 目录 1.判断链表是否…

ROS1快速入门学习笔记 - 014launch启动文件的使用方法

一、定义 Launch文件&#xff1a;通过XML文件实现多节点的配置和启动&#xff08;可自动启动ROSMaster&#xff09; 二、常用语法 1. 根标签 <launch> - launch文件中的根元素采用<launch>标签定义 <launch>表示开始&#xff1b;<launch>表示结束&…

AD | Altium Designer(原理图设计、电路仿真、PCB绘图)汉化版

Altium Designer(原理图设计、电路仿真、PCB绘图) 通知公告 Altium Designer(AD)是一种功能强大的电子设计自动化(EDA)软件。它主要用于设计和开发电子产品,如电路板(PCB)、集成电路(IC)和嵌入式系统。AD提供了完整的设计工具套件,包括原理图设计、PCB布局、仿真、设…

40.WEB渗透测试-信息收集-域名、指纹收集(2)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;39.WEB渗透测试-信息收集-域名、指纹收集&#xff08;1&#xff09; oneforall的安装前置…

基于粒子滤波器的电池剩余使用寿命计算matlab仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 粒子滤波器基础 4.2 电池剩余使用寿命建模与预测 4.3 粒子滤波器在电池寿命预测中的应用 5.完整工程文件 1.课题概述 基于粒子滤波器的电池剩余使用寿命计算。根据已知的数据&#xff0c;预测未来…

OPPO A72/A55/K7X/A53真我Q3S等手机ROOT刷机后广电卡没信号不读卡解决办法

目前运营商除了移动联通电信以外&#xff0c;还存在1个中国广电&#xff0c;广电属于第四大运营商&#xff0c;由于广电起步较晚&#xff0c;对于手机频段要求也自然不一样&#xff0c;导致目前市面上部分手机出厂没有信号或者不读卡等问题&#xff0c;特别在手机被用户自行刷机…

二叉树的遍历算法

目录 1.二叉树结构 2.广度优先搜索二叉树&#xff08;迭代算法&#xff09; 3.深度优先搜索二叉树&#xff08;递归算法&#xff09; 1.二叉树结构 一个父结点&#xff0c;至多可以连接左右两个子节点 Java构造树结构——其实是 自定义树结点类型 public class TreeNode {in…

信号,信号列表,信号产生方式,信号处理方式

什么是信号 信号在我们的生活中非常常见&#xff1b;如红绿灯&#xff0c;下课铃&#xff0c;游戏团战信号&#xff0c;这些都是信号&#xff1b;信号用来提示接收信号者行动&#xff0c;但接收信号的人接收到信号会进行一系列的行为&#xff0c;完成某个动作&#xff1b;这就…

cmake的使用方法: 多个源文件的编译

一. 简介 前面一篇文章学习了针对只有一个 .c源文件&#xff0c;如何编写 CMakeLists.txt内容&#xff0c;从而使用 cmake工具如何编译工程。文章如下&#xff1a; cmake的使用方法: 单个源文件的编译-CSDN博客 本文学习针对 多个 .c源文件&#xff0c; CMakeLists.txt文件如…