0104路径搜索和单点路径-无向图-数据结构和算法(Java)

news2024/11/15 6:46:38

文章目录

    • 2 单点路径
    • 2.1 API
    • 2.2 算法实现
    • 后记

2 单点路径

单点路径。给定一幅图和一个起点s,回答“从s到给定的目的顶点v是否存在一条路径?如果有,找出这条路径。”等类似问题。

2.1 API

单点路径问题在图的处理邻域中十分重要。根据标准设计模式,给出以下API:

public classPaths
Paths(Graph g, int s)G中找出所有起点为s的路径
booleanhasPathTo(int v)是否存在从s到v的路径
Iterable<Integer>pathTo(int v)s到v的路径,如果不存在返回null

2.2 算法实现

使用深度优先搜索搜索图中的路径非递归算法实现,源代码2.2-1如下所示:

package com.gaogzhen.datastructure.graph.undirected;

import com.gaogzhen.datastructure.stack.Stack;
import edu.princeton.cs.algs4.Graph;
import edu.princeton.cs.algs4.In;

import java.util.Iterator;
import java.util.Map;

/**
 * 单点连通性
 * @author: Administrator
 * @createTime: 2023/03/03 19:58
 */
public class DepthFirstPaths {
    /**
     * 顶点是否标记
     */
    private boolean[] marked;

    /**
     * 从起点到一个顶点的已知路径上的最后一个顶点
     */
    private int[] edgeTo;

    /**
     * 图
    */
    private Graph graph;

    /**
     * 起点
     */
    private int s;

    public DepthFirstPaths(Graph graph, int s) {
        this.graph = graph;
        this.s = s;
        int v = graph.V();
        check(s);
        marked = new boolean[v];
        edgeTo = new int[v];
        dfs();
    }

    /**
     * 搜索图g以v为起点的路径
     */
    private void dfs() {
        Stack<Entry<Integer, Iterator<Integer>>> path = new Stack<>();
        // marked[v] = true;
        if (!marked[s]) {
            // 键值对起点-起点对应邻接表迭代器压入栈中
            marked[s] = true;
            Iterable<Integer> iterable = graph.adj(s);
            Iterator<Integer> it;
            if (iterable != null && (it = iterable.iterator()) != null){
                path.push(new Entry<>(s, it));
            }
        }
        while (!path.isEmpty()) {
            Entry<Integer, Iterator<Integer>> entry = path.pop();
            int x;
            Iterator<Integer> it = entry.getValue();
            Integer f = entry.getKey();
            while (it.hasNext()) {
                // 当前顶点对应的邻接表迭代器还有元素,获取下一个元素
                x = it.next();
                if (!marked[x]) {
                    // 顶点未被标记,标记顶点且标记路径x->f
                    // f是x所在邻接表对应的顶点
                    marked[x] = true;
                    edgeTo[x] = f;
                    if (it.hasNext()) {
                        // 邻接表迭代器还有元素,重新压入栈
                        path.push(entry);
                    }
                    // 按照深度优先原则,把新标记顶点对应的键值对压入栈中,在下次循环时优先访问
                    Iterable<Integer> iterable = graph.adj(x);
                    if (iterable != null && (it = iterable.iterator()) != null){
                        path.push(new Entry<>(x, it));
                    }
                    break;
                }
            }

        }
    }

    /**
     * 检测索引是否在范围之内
     * @param i 给定索引
     */
    private void check(int i) {
        if (i < 0 || i > graph.V() - 1) {
            throw new IndexOutOfBoundsException("索引越界异常");
        }
    }

    /**
     * 判断是否存在起点s到v的路径
     * @param x 给定顶点
     * @return
     */
    public boolean hashPathTo(int x) {
        check(x);
        return marked[x];
    }

    /**
     * s到v的路径,如果不存在返回null
     * @param x 指定的顶点
     * @return  起点到指定顶点的路径
     */
    public Iterable<Integer> pathTo(int x) {
        // 判断v和起点间是否存在路径
        if (!hashPathTo(x)) {
            // 不存在返回null
            return null;
        }
        // 栈记录x到起点的路径
        Stack<Integer> path = new Stack<>();
        // edge[]是一棵父链接表示的树,所以从已知路径的最后一个顶点开始沿父链接遍历,直到起点
        for (int p = x; p != s; p = edgeTo[p]) {
            path.push(p);
        }
        // 加入起点
        path.push(s);
        return path;
    }

}

测试:

    public static void testPaths() {
        String path = "H:\\gaogzhen\\java\\projects\\algorithm\\asserts\\maze.txt";
        In in = new In(path);
        Graph graph = new Graph(in);
        int s = 0;
        DepthFirstPaths depthFirstPaths = new DepthFirstPaths(graph, s);

        int v = 4;
        System.out.println(depthFirstPaths.hashPathTo(v));
        System.out.println(depthFirstPaths.pathTo(v));
    }
   // 测试结果
   true
[0, 2, 3, 5]

算法分析:

  • 该算法基于深度优先搜索实现的,可以参考上一篇 0103深度优先搜索和单点连通-无向图-数据结构和算法(Java)

  • 这里添加了一个实例变量edgeTo[]整形数组,用来记录从每个与s连通的顶点回到起点s的路径。

  • 在由边v-w第一次访问任意顶点w时,将edgeTo[w]设置为v来记住这条路径。换句话说,v-w是从s到w的路径上的最后一条已知的便。

  • 搜索的结果是一棵以起点为根结点的树,edgeTo[]是一棵由父链接表示的树。如下图所示:在这里插入图片描述

  • pathTo()通过x自下沿路径向上遍历整棵树,x设为edgeTo[x],将经过的顶点压入栈中,返回Iterable对象帮助用例遍历s到v的路径。

    • edgeTo[]是一棵由父链接表示的树,x=edgeTo[x]保证向上遍历

命题A:使用深度优先搜索得到从给定起点到任意标记顶点的路径所需时间与路径的长度成正比。

证明:根据已访问过的订单数量的归纳可得,DepthFirstPaths中的edgeTo[]数组表示一棵以起点为根结点的树。pathTo方法构造路径所需时间和路径长度成正比。

后记

如果小伙伴什么问题或者指教,欢迎交流。

❓QQ:806797785

⭐️源代码仓库地址:https://gitee.com/gaogzhen/algorithm

参考链接:

[1][美]Robert Sedgewich,[美]Kevin Wayne著;谢路云译.算法:第4版[M].北京:人民邮电出版社,2012.10.p342-344.

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

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

相关文章

PHP, Python和Java的区别

PHP, Python和Java是广泛使用的编程语言。每种编程语言都有其独特的优点和缺点。在本文中&#xff0c;我们将对这些编程语言进行分析&#xff0c;并探讨它们在不同应用场景中的最佳用途。一、PHPPHP是一种广泛使用的Web编程语言&#xff0c;它可以在服务器上运行&#xff0c;并…

程设 | week2:STL

&#x1f4da;回顾C &#x1f407;struct和class 从功能上说&#xff0c;struct和class几乎没什么区别在不显式声明的情况下&#xff0c;struct成员默认为public&#xff0c;class默认为private和c语言的struct不同&#xff0c;c的struct可以定义成员函数&#xff0c;重载运算…

G6绘制树形图(自定义节点、自定义边、自定义布局)

目录1 设计节点1.1 定义节点和文本1.2 增加节点1.3 自定义节点样式2 树图配置2.1 允许使用自定义dom节点2.2 内置行为自定义边layout布局demo1 设计节点 在 registerNode 中定义所有的节点 G6.registerNode(tree-node, {drawShape: function drawShape(cfg, group) {定义图中…

aws appconfig 理解和使用appconfig对应用程序进行动态配置

参考资料 Automating Feature Release using AWS AppConfig Integration with AWS CodepipelineDeploying application configuration to serverless: Introducing the AWS AppConfig Lambda extensionCreate a pipeline that uses Amazon AppConfig as a deployment provider…

秒懂算法 | 搜索基础

本篇介绍了BFS和DFS的概念、性质、模板代码。 01、搜索简介 搜索,就是查找解空间,它是“暴力法”算法思想的具体实现。 暴力法(Brute force,又译为蛮力法):把所有可能的情况都罗列出来,然后逐一检查,从中找到答案。这种方法简单、直接,不玩花样,利用了计算机强大的…

JavaScript 中的 String 类型 模板字面量定义字符串

ECMAScript 6新增了使用模板字面量定义字符串的能力。与使用单引号或双引号不同&#xff0c;模板字面量保留换行字符&#xff0c;可以跨行定义字符串&#xff1a; let str1 早起的年轻人\n喜欢经常跳步;let str2 早起的年轻人喜欢经常跳步;console.log(str1);// 早起的年轻人…

【游戏逆向】游戏玩家技能冷却分析

技能冷却对于不同的游戏有不同的存放方式,而技能冷却的遍历也大多不会和技能的普通属性放在一起,在《在**明月刀》这款游戏中,技能的冷却判断格外重要,因为技能的连贯性对打怪的效率影响很大。 我们需要找一个冷却相对较长的技能用来进行扫描和过滤,一般选择几十秒即可,…

【本周特惠课程】基于GAN的图像增强理论与实践(涵盖图像降噪、色调映射、去模糊、超分辨、修复等方向)...

前言欢迎大家关注有三AI的视频课程系列&#xff0c;我们的视频课程系列共分为5层境界&#xff0c;内容和学习路线图如下&#xff1a;第1层&#xff1a;掌握学习算法必要的预备知识&#xff0c;包括Python编程&#xff0c;深度学习基础&#xff0c;数据使用&#xff0c;框架使用…

Windows扫描工具RunScanner使用实验(21)

实验目的 掌握利用Runscanner扫描和分析电脑&#xff1b;预备知识 RunScanner是一个完全免费的Windows系统工具,您可以用它轻松地将隐藏在您系统中的autostart程序,spyware,adware,主页劫持,未经认证的驱动揪出来,并可以导入和导出报告以帮助别人或获取帮助.目前它可以…

华为OD机试题,用 Java 解【素数之积】问题

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典使用说明 参加华为od机试,一定要注意不…

C++中的利器——模板

前文本文主要是讲解一下C中的利器——模板&#xff0c;相信铁子们在学完这一节后&#xff0c;写代码会更加的得心应手&#xff0c;更加的顺畅。一&#xff0c;泛型编程想要学习模板&#xff0c;我们要先了解为什么需要模板&#xff0c;我们可以看看下面这个程序。int add(int&a…

MDK Keil5 创建Stm32工程-理论篇(这里以Stm32F103Zet6为例)

一、文件夹创建与文件说明整个工程可以粗略的划分为几个文件夹&#xff1a;BSP底层驱动比如GPIO\Timer等驱动文件CMSIS内核相关的文件Firmware生成的固件下载文件Mycode用户编写的相关文件&#xff0c;主要编写的文件都在这个文件夹里Project工程文件startup芯片启动文件STM32F…

1.C#与.NET简介

目录 一、C#语言及其特点 二、C#与.NET Framework/.NET Core关系 三、C#应用开发 四、案例展示 五、学习环境 一、C#语言及其特点 C#是美国微软公司发布的一种面向对象的&#xff0c;运行于 .NET Framework 和 .NET Core &#xff08;完全开源&#xff0c;跨平台&#xff…

什么是LSM-Tree

前言 十多年前&#xff0c;谷歌发布了大名鼎鼎的"三驾马车"的论文&#xff0c;分别是GFS(2003年)&#xff0c;MapReduce&#xff08;2004年&#xff09;&#xff0c;BigTable&#xff08;2006年&#xff09;&#xff0c;为开源界在大数据领域带来了无数的灵感&#…

unity的安装配置和第一个游戏-unity开学第一课

许多的小伙伴学编程语言其实是因为玩游戏&#xff0c;玩着玩着就想写游戏了&#xff0c;于是开始学习c学习C#学习java&#xff0c;但相比之下C#的操作会更加容易&#xff0c;所以就开始学习unity来编游戏了。这里就就算是unity开学第一课啦-unity的安装配置和第一个游戏。 文章…

Maven项目的创建

目录 1.创建java项目 1.1 新建项目​编辑 2 创建web项目 2.1 新建项目 2.2 启动项目 2.2.1 修改jdk的版本 2.2.2 设置单元测试的版本 2.2.3 删除pluginManagement标签 2.2.4添加web部署插件 2.2.5 启动项目 1.创建java项目 1.1 新建项目 创建resources目录 利用maven…

类模板函数模板从属类型

准备看个项目找实习&#xff0c;边看边学&#xff0c;一看到处都是template 和typename&#xff0c;好几年前学的C都忘记光了&#xff0c;在这里先做个笔记复习一下。template <class T> T abs(T x) {if(x < 0) return -x;return x; } int main() {int x 1;cout <…

PyQt5可视化 7 饼图和柱状图实操案例 ①Qt项目的创建

目录 一、新建Qt项目 二、添加组件和布局 三、添加资源 1. 新建资源文件 2. 添加图标资源 四、frameHead 1. toolBtnGenData 2. toolBtnCounting 3. comboTheme 4. comboAnimation 5. Horizontal Spacer 6. toolBtnQuit 7. 设置toolBtnQuit的功能 8. frameHead的…

设计模式(十六)----结构型模式之代理享元模式

1、概述 定义&#xff1a; 运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似对象的开销&#xff0c;从而提高系统资源的利用率。 2 结构 享元&#xff08;Flyweight &#xff09;模式中存在以下两种状…

CentOS系统安装部署Zabbix

1、LNMP环境部署&#xff1a; 1&#xff09;系统升级&#xff1a; yum update -y 2&#xff09;安装依赖库&#xff1a; yum install -y zlib pcre pcre-devel openssl openssl-devel 3&#xff09;添加用户www&#xff0c;那么也自动创建了用户组&#xff1a;www&#xf…