0106广度优先搜索和最短路径-无向图-数据结构和算法(Java)

news2025/7/18 21:17:14

1 单点最短路径

单点最短路径。 给定一幅图和一个起点s,回答“从s到给定目的顶点v是否存在一条路径?如果有,找出其中最短的那条(所含边数最少)。“等类似问题。

深度优先搜索在这个问题上没有什么作为,因为它遍历整个图的顺序和找出最短路径的目标没有任何关系。相比之下,广度优先搜索正好可以解决这个问题。

分析:

  • 要找的从s到v的最短路径,从s开始,在所有由一条边就可以到达的顶点中寻找v,找到标记结束。
  • 如果没有找到,我们继续在于s距离2条边的顶点中查找v,如此一直进行。
  • 最后也没有找到,那么说明s到给定顶点v不存在路径,此图为非连通图。

结构选择:

  • 广度优先搜索中,我们希望按照与起点的距离顺序遍历所有顶点,所以我们选择队列(先入先出)。

2 广度优先搜索实现

实现代码如下:

package com.gaogzhen.datastructure.graph.undirected;

import edu.princeton.cs.algs4.*;

/**
 * 最短路径算法
 * @author: Administrator
 * @createTime: 2023/03/07 21:04
 */
public class BreadthFirstDirectedPaths {
    private static final int INFINITY = Integer.MAX_VALUE;

    /**
     * 标记顶点是否与起点连通
     */
    private boolean[] marked;

    /**
     * 表示顶点到与该顶点连通的顶点间最短路径
     */
    private int[] edgeTo;

    /**
     * 顶点到起点之间的边数
     */
    private int[] distTo;

    /**
     * 计算从指定顶点到起点最短路径
     * @param G 无向图
     * @param s 起点
     * @throws IllegalArgumentException unless {@code 0 <= v < V}
     */
    public BreadthFirstDirectedPaths(Graph G, int s) {
        marked = new boolean[G.V()];
        distTo = new int[G.V()];
        edgeTo = new int[G.V()];
        for (int v = 0; v < G.V(); v++) {
            distTo[v] = INFINITY;
            edgeTo[v] = -1;
        }
        validateVertex(s);
        bfs(G, s);
    }

    /**
     * 计算多个起点到指定顶点之间的最短路径
     * @param G 无向图
     * @param sources 多个起点集合
     * @throws IllegalArgumentException if {@code sources} is {@code null}
     * @throws IllegalArgumentException unless each vertex {@code v} in
     *         {@code sources} satisfies {@code 0 <= v < V}
     */
    public BreadthFirstDirectedPaths(Graph G, Iterable<Integer> sources) {
        marked = new boolean[G.V()];
        distTo = new int[G.V()];
        edgeTo = new int[G.V()];
        for (int v = 0; v < G.V(); v++) {
            distTo[v] = INFINITY;
            edgeTo[v] = -1;
        }
        validateVertices(sources);
        bfs(G, sources);
    }

    /**
     * 广度优先搜索从指定顶点到起点最短路径
     * @param G 无向图
     * @param s 起点
     */
    private void bfs(Graph G, int s) {
        Queue<Integer> q = new Queue<Integer>();
        marked[s] = true;
        distTo[s] = 0;
        q.enqueue(s);
        while (!q.isEmpty()) {
            int v = q.dequeue();
            for (int w : G.adj(v)) {
                if (!marked[w]) {
                    edgeTo[w] = v;
                    distTo[w] = distTo[v] + 1;
                    marked[w] = true;
                    q.enqueue(w);
                }
            }
        }
    }

    // BFS from multiple sources
    private void bfs(Graph G, Iterable<Integer> sources) {
        Queue<Integer> q = new Queue<Integer>();
        for (int s : sources) {
            marked[s] = true;
            distTo[s] = 0;
            q.enqueue(s);
        }
        while (!q.isEmpty()) {
            int v = q.dequeue();
            for (int w : G.adj(v)) {
                if (!marked[w]) {
                    edgeTo[w] = v;
                    distTo[w] = distTo[v] + 1;
                    marked[w] = true;
                    q.enqueue(w);
                }
            }
        }
    }

    /**
     * 起点s与指定顶点v之间是否有路径(连通)
     * @param v the vertex
     * @return {@code true} if there is a directed path, {@code false} otherwise
     * @throws IllegalArgumentException unless {@code 0 <= v < V}
     */
    public boolean hasPathTo(int v) {
        validateVertex(v);
        return marked[v];
    }

    /**
     * 返回指定顶点v到起点直接的最短路径(边数)}?
     * @param v the vertex
     * @return the number of edges in such a shortest path
     *         (or {@code Integer.MAX_VALUE} if there is no such path)
     * @throws IllegalArgumentException unless {@code 0 <= v < V}
     */
    public int distTo(int v) {
        validateVertex(v);
        return distTo[v];
    }

    /**
     * 返回指定顶点v到起点直接的最短路径,没有返回null
     * @param v the vertex
     * @return the sequence of vertices on a shortest path, as an Iterable
     * @throws IllegalArgumentException unless {@code 0 <= v < V}
     */
    public Iterable<Integer> pathTo(int v) {
        validateVertex(v);

        if (!hasPathTo(v)) return null;
        Stack<Integer> path = new Stack<Integer>();
        int x;
        for (x = v; distTo[x] != 0; x = edgeTo[x])
            path.push(x);
        path.push(x);
        return path;
    }

    // throw an IllegalArgumentException unless {@code 0 <= v < V}
    private void validateVertex(int v) {
        int V = marked.length;
        if (v < 0 || v >= V)
            throw new IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1));
    }

    // throw an IllegalArgumentException if vertices is null, has zero vertices,
    // or has a vertex not between 0 and V-1
    private void validateVertices(Iterable<Integer> vertices) {
        if (vertices == null) {
            throw new IllegalArgumentException("argument is null");
        }
        int V = marked.length;
        int count = 0;
        for (Integer v : vertices) {
            count++;
            if (v == null) {
                throw new IllegalArgumentException("vertex is null");
            }
            validateVertex(v);
        }
        if (count == 0) {
            throw new IllegalArgumentException("zero vertices");
        }
    }
}

队列保存所有已被标记但其邻接表未被检查过的顶点。先将起点加入队列,然后重复一下步骤知道队列为空。

  • 取出队列中的下一个顶点v并标记它。
  • 将与v相邻的所有未被标记过的顶点加入队列。

说明:

  • edgeTo[]数组结果,也是一棵用父链接表示的根结点为s的树
    • 多起点中,则以各自起点为根结点的树组成的森林。
  • distTo[]表示到起点的路径长度,即边数。代码distTo[w] = distTo[v] + 1;当前顶点路径长度为其父顶点路径长度+1,起点为0。
  • 与算法第四版不同的地方只是在初始化edgeTo为-1表示根结点;算法第四版默认都是0。

以之前无向图(6个顶点,8条边)为例单起点搜索索引起点为0(单起点的路径结果:

在这里插入图片描述

多起点(0,2)搜索结果如下图所示:

在这里插入图片描述

多起点搜索很少用到,一般情况下我们讨论最短路径默认为单点最短路径。

3 总结

命题B。对于从s可达的任意顶点v,广度优先搜索都能找到一条从s到v的最短路径(没有其他从s到v的路径所含有的边比这条路径少。

证明:由归纳易得队列总是包含林哥或者多个到起点的距离为k的顶点,之后是零个或者多个到起点为k+1的顶点,k为整数,起始值为0.这意味着顶点是按照它们和s的距离顺序加入或者离开队列。从顶点v加入队列到它离开队列之前,不可能找出到v的更短路径,而在v离开队列之后发现的所有能够到达v的路径都不可能短于v在树中的路径长度。

命题B(续)。广度优先搜索所需的时间在最坏情况下和V+E成正比。

证明:广度优先搜索标记所有与s连通的顶点所需的时间与它们的度数之和成正比。如果图是连通的,这个和就是所有顶点的度数之和,也就是2E。

广度优先搜索也可以解决单点连通问题,它检查所有与起点连通的顶点和边的方法取决于查找的能力。代码如下:

private void bfs(Graph G, int s) {
    Queue<Integer> q = new Queue<Integer>();
    marked[s] = true;
    q.enqueue(s);
    while (!q.isEmpty()) {
        int v = q.dequeue();
        for (int w : G.adj(v)) {
            if (!marked[w]) {
                marked[w] = true;
                q.enqueue(w);
            }
        }
    }
}

后记

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

❓QQ:806797785

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

参考链接:

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

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

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

相关文章

个人创业做什么好?哪些互联网创业项目可长期收益?

打工没前途&#xff0c;这是现在年轻人看透了的一个事情&#xff0c;日复一日地工作&#xff0c;不如自己创业挣钱&#xff0c;那么个人创业做什么好呢&#xff1f;哪些项目可以长期稳定收益呢&#xff1f; 一、高体力项目不要做&#xff1b; 创业项目有很多&#xff0c;尤其是…

RK3588平台开发系列讲解(同步与互斥篇)自旋锁介绍

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、自旋锁介绍二、自旋锁相关的函数1、普通场景2、进程上下文和下半部3、中断相关三、相关结构体四、函数实现1、初始化2、获取自旋锁沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇介绍自旋锁的使用和基…

Clickhouse数据去重

1. Hive去重 先以两个简单的sql启发我们的话题 select count(distinct id)from order_combine;select count(id) from (select id from order_combine group by id ) t;从执行日志当中我们可以看到二者的差异&#xff08;只摘取关键部分&#xff09; # distinctStage-Stage…

kube-scheduler

kube-scheduler&#xff0c;它是 k8s 的默认调度器&#xff0c;负责为新创建出来的 pod寻找一个最合适的节点&#xff0c;这里的“最合适”指两种最优解&#xff1a;从集群中的所有节点中找出的全局最优解&#xff0c;和从集群中的部分节点中找出的局部最优解。它们分别可以解决…

电气系统中防雷接地保护的综合解决方案

防雷接地保护是通过导体和接地&#xff0c;可靠地连接一种保护性接线方法&#xff0c;在该保护性接线方法中&#xff0c;可能会在绝缘材料损坏后或在其他情况下对电器的金属部分&#xff08;即与带电部分绝缘的金属结构部分&#xff09;进行绝缘。接地保护系统仅具有相线和零线…

VSCode使用技巧,代码编写效率提升2倍以上!

VSCode是一款开源免费的跨平台文本编辑器&#xff0c;它的可扩展性和丰富的功能使得它成为了许多程序员的首选编辑器。在本文中&#xff0c;我将分享一些VSCode的使用技巧&#xff0c;帮助您更高效地使用它。 1. 插件 VSCode具有非常丰富的插件生态系统&#xff0c;通过安装插…

大数据分析案例-基于逻辑回归算法构建微博评论情感分类模型

🤵‍♂️ 个人主页:@艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞👍🏻 收藏 📂加关注+ 喜欢大数据分析项目的小伙伴,希望可以多多支持该系列的其他文章 大数据分析案例合集…

【WEB前端进阶之路】 HTML 全路线学习知识点梳理(下)

前言 本文是HTML零基础小白学习系列的第三篇文章&#xff0c;点此阅读 上一篇文章 文章目录前言十五.HTML布局1.使用div元素添加网页布局2.使用table元素添加网页布局十六.HTML表单和输入1.文本域2.密码字段3.单选按钮4.复选框5.提交按钮十七.HTML框架1.iframe语法2.iframe设置…

java中如何判断map是否为空

java中判断map是否为空的方法是&#xff1a;利用isEmpty()函数来判断。函数介绍&#xff1a;isEmpty()是Java中用于判断某种容器是否有元素的系统库函数。如用来判断ArrayList&#xff0c;HashSet&#xff0c;HashMap是否有元素等。在Java中&#xff0c;可以用isEmpty();判断一…

燃料电池聚合物电解质膜高低温退化性能测试中的TEC半导体制冷温控解决方案

摘要&#xff1a;针对燃料电池质子交换膜高低温退化机理表征&#xff0c;基于德国慕尼黑工业大学团队提出的替代环境试验箱的TEC半导体制冷温控方案及其功能指标&#xff0c;本文给出此方案具体实施内容的补充&#xff0c;详细介绍了用于TEC半导体制冷温控系统的PID调节器和大功…

Springboot项目连接neo4j数据库

首先创建一个springboot项目&#xff0c;这里不再介绍。1 导入依赖包连接neo4j数据库的依赖包<dependency><groupId>org.neo4j</groupId><artifactId>neo4j-ogm-http-driver</artifactId><version>2.1.5</version> </dependency&…

人工智能算法几个重要指标

一、几个前置概念 TP&#xff08;True Positive&#xff09;&#xff1a;正确的正例&#xff0c;正类被判定成正类 FN&#xff08;False Negative&#xff09;&#xff1a;错误的反例&#xff0c;漏报&#xff0c;正类被判定为假类 FP&#xff08;False Positive&#xff09…

dp之数位dp---(度的数量)

题目&#xff1a; 思路&#xff1a; 首先对题目意思进行分析&#xff1a;恰好等于 K 个互不相等的 B 的整数次幂之和&#xff0c;这句话的意思是说对于某一个B进制数x说&#xff0c;x只有k位上只有1&#xff0c;其他位都为0。然后让你求区间[X,Y]的满足条件的数字有多少&#x…

MyBatis开发详解

MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO&#xff08;Plain Old Java Objects&am…

信息系统基本知识(五)信息系统安全技术

大纲 信息系统与信息化信息系统开发方法常规信息系统集成技术软件工程新一代信息技术信息系统安全技术信息化发展与应用信息系统服务管理信息系统服务规划企业首席信息管及其责任 1.6 信息系统安全技术 1.6.1 信息系统安全的有关概念 信息安全的概念&#xff1a;信息安全强…

机器人向生产力系统迈进,优艾智合稳步“从1到100”

在中国&#xff0c;机器人的“成长”总是令人惊讶。这些“钢铁生命”和“芯片生命”&#xff0c;在工厂流水线、物流仓储园区、机房电站飞速复制&#xff0c;充当产业的手、眼和大脑。国际机器人联合会IFR的数据显示&#xff0c;2020-2024年&#xff0c;中国机器人市场规模CAGR…

源码解析——HashMap

源码解析——HashMap1. 什么 是HashMap2. 为什么要使用HashMap3. HashMap的使用4. 源码解析4.1 关键问题4.1 存储结构4.2 HashMap 的容量和负载因子4.3 初始化过程4.3 put() 方法实现原理4.3.1 hash()4.3.2 resize()4.4 get() 方法实现原理5. 面试题总结6. ConcurrentHashmap(J…

【办公类-16-06】“2022下学期 总园活动室(沙水+建构)排班表”(python 排班表系列)

背景需求&#xff1a;最近保教主任一直在为总园的活动室安排而头疼不已&#xff0c;和组长们商议许久&#xff0c;依旧无法合理把活动室安排好。3月2日下午&#xff0c;听主任和游戏室成员聊了一个小时的排班&#xff0c;结论是除沙水和建构外&#xff0c;其余空余时间都是”自…

【RGB3DS道路检测车智慧运维解决方案】助力城市道路运维数字化转型

随着数字城市建设的全面推进&#xff0c;交通运维数字化转型也逐步进入新的层次。道路表观病害检测作为养护运维的基础和关键环节&#xff0c;亟待投入更多关注。 针对国家对交通运维数字化转型的相关要求与及时有效评估路面健康情况的需求&#xff0c;博雅弘拓科技力推【RGB3…

互联网大厂效率到底有多高?且看大腕怎么说

互联网公司的效率到底有多高&#xff1f; 看抖音创始人张一鸣怎么说 趣讲大白话&#xff1a;组织能力是关键 【趣讲信息科技96期】 ******************************* 对组织而言需要把优秀的标准清晰无误的传递且不断精进。含糊和混淆其实是牺牲。——抖音创始人张一鸣。 把信…