基础图算法:广度搜索优先(BFS)

【数据结构与算法】3.(单向、无向、带权)图,广度、深度优先搜索,贪心算法 单向图、无向图、带权图、广度优先搜索、深度优先搜索、贪心算法 阅读详情

什么是图?这里有对图的描述https://www.jianshu.com/p/bce71b2bdbc8

那么广度搜索优先算法与深度搜索优先算法的作用就是遍历整个图数据的两种算法,两种算法的核心都是对图的遍历,都属于对贪心算法的体现。

广度优先算法(BFS又称为宽度优先算法)

广度优先算法是遍历完整图的一种遍历算法,也是很多高级算法的基础,例如Dijkstra又称迪杰斯特拉算法(用来计算正向最短路径算法),Kruskal 又称克鲁斯卡尔算法(用来计算最小生成树)。BFS算法的核心类似于广播形式的由内到外一层一层进行搜索。直到遍历最外一层结构。通常我们需要依赖与队列(先进先出)数据结构完成整体的遍历。后面我会通过实际的栗子来介绍BFS的应用场景和实际用处。

如图所示为一个基本图

如何区遍历以上图结构.

第一步:准备创建一个空队列中,以及一个能保证数据唯一性的集合(我这里用set保存值为顶点id)来保存遍历过的点,我们假设以1顶点为(可以从任意顶点开始)开始,将其放入队列中。

第二步:从队列中获取1顶点,获取1顶点下连接的2,3点。判断是否在set中已存在该顶点,如果不存在写入到队列中。此时第一层已遍历完成。

第三步:从队列中取出2顶点,获取2顶点下连接4,5,6顶点,并判断是该顶点否在set中已存在,如果不存在则写入到队列中。再拿出3顶点获取5,7顶点,因为5顶点再set中已存在,不需要再写入队列.此时第二层已遍历完成

循环取出队列中的顶点,直到最后队列为空队列此时,所有图中顶点已遍历成功

对于整个图结构遍历的时间复杂度为O(n+e) n为节点数 e为边数

 

在我们的项目中有以下需求图如下所示:当我们要删除D顶点时,我们要级连删除D顶点 。已知顶点集合,边集合。

解决思路:先移除被删除点以及与顶点关联边数据,通过BFS算法获取图中取出删除点后仍然与A点关联的其它顶点即可

这里通过JAVA代码实现

1:定义图,边,顶点实体类

package com.demo.kafkaDemo.BFS;

import lombok.*;

import java.io.Serializable;
import java.util.List;

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class Graphs implements Serializable {

        //节点列表 包含所有节点信息
        private List<Graphs.Vertex> vertexs;

        //关系信息
        private List<Graphs.Edge> edges;

        @Data
        @Builder
        @NoArgsConstructor
        @AllArgsConstructor
        public static class Vertex implements Serializable {

            //是否为主节点
            private boolean isMaster = false;

            //顶点id
            private String id;

            //顶点描述
            private String content;

        }

        @Data
        @Builder
        @NoArgsConstructor
        @AllArgsConstructor
        /**
         * 关系描述 记录起始-到终止几点的关系描述
         */
        public static class Edge implements Serializable {
            //起始顶点-Id
            private String from;

            //终止顶点-Id
            private String to;

            //顶点关系描述
            private String description;

        }
        
    }

2:构建测试数据,以及实现功能需求


import java.util.*;
import java.util.stream.Collectors;

import static com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util.println;

public class Test {


    public static void main(String[] args) {

        //创建测试顶点 假设已A为开始顶点
        Graphs.Vertex A = Graphs.Vertex.builder().id("A").content("A").isMaster(true).build();

        Graphs.Vertex B = Graphs.Vertex.builder().id("B").content("B").isMaster(false).build();

        Graphs.Vertex C = Graphs.Vertex.builder().id("C").content("C").isMaster(false).build();

        Graphs.Vertex D = Graphs.Vertex.builder().id("D").content("D").isMaster(false).build();

        Graphs.Vertex E = Graphs.Vertex.builder().id("E").content("E").isMaster(false).build();

        Graphs.Vertex F = Graphs.Vertex.builder().id("F").content("F").isMaster(false).build();

        Graphs.Vertex G = Graphs.Vertex.builder().id("G").content("G").isMaster(false).build();

        Graphs.Vertex H = Graphs.Vertex.builder().id("H").content("H").isMaster(false).build();

        Graphs.Vertex I = Graphs.Vertex.builder().id("I").content("I").isMaster(false).build();

        List<Graphs.Vertex> vertes = new ArrayList<>(9);

        vertes.add(A);vertes.add(B);vertes.add(C);vertes.add(D);
        vertes.add(E);vertes.add(F);vertes.add(G);vertes.add(H);
        vertes.add(I);

        List<Graphs.Edge> edges = new ArrayList<>(10);

        //这里我们定义了A-I共9个顶点 它们之间的关系为
        Graphs.Edge e1 = Graphs.Edge.builder().from("A").to("B").description("A与B之间的关系").build();

        Graphs.Edge e2 = Graphs.Edge.builder().from("A").to("C").description("A与C之间的关系").build();

        Graphs.Edge e3 = Graphs.Edge.builder().from("B").to("F").description("B与F之间的关系").build();

        Graphs.Edge e4 = Graphs.Edge.builder().from("C").to("D").description("C与D之间的关系").build();

        Graphs.Edge e5 = Graphs.Edge.builder().from("D").to("F").description("D与F之间的关系").build();

        Graphs.Edge e6 = Graphs.Edge.builder().from("D").to("E").description("D与E之间的关系").build();

        Graphs.Edge e7 = Graphs.Edge.builder().from("D").to("G").description("D与G之间的关系").build();

        Graphs.Edge e8 = Graphs.Edge.builder().from("E").to("H").description("E与H之间的关系").build();

        Graphs.Edge e9 = Graphs.Edge.builder().from("G").to("H").description("G与H之间的关系").build();

        Graphs.Edge e10 = Graphs.Edge.builder().from("H").to("I").description("H与I之间的关系").build();

        edges.add(e1);edges.add(e2);edges.add(e3);edges.add(e4);edges.add(e5);
        edges.add(e6);edges.add(e7);edges.add(e8);edges.add(e9);edges.add(e10);


        //被移除的顶点id
        String removeId = "D";

        //将边关系进行变更为map集合 k 为边中fromId List<V>为边实体
        Map<String,List<Graphs.Edge>> mEdges = new HashMap<>();

        //保存from顶点到关联集合顶点
        edges.forEach(edge->{

            //移除被删除顶点关联的边
           String toId =  edge.getTo();
           if(!removeId.equals(toId)){
               List<Graphs.Edge> edgs =  mEdges.get(edge.getFrom());
               if(edgs == null){
                   edgs = new ArrayList<>();
               }
               edgs.add(edge);

               mEdges.put(edge.getFrom(),edgs);
           }

        });


        //构建队列 这里使用java自带的LinkedList
        Queue<String> queue = new LinkedList<>();

        //访问过所有顶点 具有唯一性
        HashSet<String> wySet = new HashSet<>();

        //写入master 节点即开头顶点 唯一标示 从A开始遍历
        queue.add("A");
        wySet.add("A");

        while(!queue.isEmpty()){

            //获取当前点id
            String curId = queue.poll();

            //获取该顶点下一层关联所有顶点
            List<Graphs.Edge> relations = mEdges.get(curId);

            //代表为最后一层顶点
            if(relations == null) continue;

            for (Graphs.Edge edg : relations) {
                String nextId = edg.getTo();
                if (!wySet.contains(nextId)) {
                    queue.add(nextId);
                    wySet.add(nextId);
                }
            }
        }

        //去除不存在节点
        vertes = vertes.stream().filter(vertex -> wySet.contains(vertex.getId())).collect(Collectors.toList());

        //去除不存在的边
        edges = edges.stream().filter(edge ->     (wySet.contains(edge.getFrom()) && wySet.contains(edge.getTo()))).collect(Collectors.toList());


        //验证是否级连删除点 边
        vertes.stream().forEach(vertex -> println(vertex.getContent()));

        edges.stream().forEach(ed -> println(ed.getDescription()));

    }


}

 

《算法导论》学习分享——22. 基本的图算法(BFS,DFS,拓扑排序,强连通分量) 22. 基本的图算法 本章介绍图的表示和搜索。 许多的图算法在一开始都会先通过搜索来获得图的结构,其他一些图算法则是对基本的搜索加以优化。 可以说,图的搜索技巧是整个图算法领域的核心。 图的表示 G=(V,E)G=(V,E)G = (V, E) 图G由结点的集合V 和 边的集合E 组成 可以用两种方法表示,一种是邻接链表(下图b),一种是邻接矩阵(下图c)。 邻接链表一... 阅读详情

相关推荐

Python 图解算法 递归/快速排序/散列表/广度优先搜索

图解算法 递归/快速排序/散列表/广度优先搜索 1.递归 每个递归函数都有两个条件:基线条件和递归条件 简单例子:实现sum函数 # 1.实现sum函数 def sumNumber(arr): if arr==[]: return 0 else: print(arr.pop()) return arr.pop()+sumNumber(arr) print(sumNumber([2,5,7,10])) 2.快速排序 O(nlogn)

weixin_39419220的博客 756

听我给你吹——Dijkstra算法

听我给你吹——Dijkstra算法 注意!!! 文章转自古月居 博主:管理大大说我昵称违规 原文链接:听我给你吹——Dijkstra算法 正文: 一直玩的ROS的驱动开发,开发导航基本靠调包,奈何这次给的太多,来位大家分享一些自己知道的关于“移动机器人路径规划”的知识! ​ 不管是搞雷达SLAM还是视觉SLAM,ROS绝对是必不可少的好东西!不过大多数也就是在仿真跑起来看到效果,好点的能有个车来真实的跑跑,雷达建图导航确实炫酷,很容易吸引到学弟学妹们的崇拜! ​ 在操作ROS导航的时候,我们需要先从RVIZ

weixin_51852924的博客 1271

【雷达信号处理实战】从原理到代码:脉冲多普勒(PD)处理全流程解析与MATLAB仿真

本文深入解析了脉冲多普勒(PD)雷达信号处理的核心原理与全流程。通过剖析多普勒效应、脉冲压缩与慢时间FFT等关键技术,并结合详细的MATLAB仿真代码,手把手指导如何从信号建模、回波模拟到最终生成距离-多普勒谱,实现运动目标的精确测距与测速,直观展示了相参积累带来的显著性能增益。

pca5navigator的博客 953

《算法图解》简单学习 ^_^

门外汉 初学算法

waow的进阶之路 783

Sigrity IBIS建模实战:如何用T2B工具快速转换SPICE模型(附避坑指南)

本文详细介绍了如何使用Sigrity T2B工具将SPICE模型高效转换为IBIS模型,涵盖从环境配置、模型预处理到转换流程和验证策略的全过程。通过实战案例和避坑指南,帮助硬件工程师掌握高速电路设计中的IBIS建模技术,提升信号完整性分析效率。

weixin_29243279的博客 395

ZYNQ实战:手把手教你用AXI4-Full IP核打通PL与PS的DDR数据通道

本文提供了一份详细的ZYNQ实战指南,手把手教你创建并使用具备AXI4-Full Master接口的自定义IP核,实现PL(可编程逻辑)通过AXI HP接口直接读写PS(处理系统)的DDR内存。文章涵盖了从Vivado硬件设计、IP核配置、地址映射到Vitis软件验证的完整流程,并深入解析了数据一致性(禁用Cache)等关键要点,旨在帮助开发者掌握ZYNQ异构计算中高效数据搬运的核心技术。

weixin_29193359的博客 284

【算法】贪心&BFS&DFS

贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。BFS广度优先,DFS深度优先。

日拱一卒,功不唐捐。 2094

AVS3代码阅读HPM4.0

参考AVS3代码阅读(HPM6.0)(一.整体架构以及CU划分部分代码) 版本:HPM4.0 核心文件:app_encoder.c   要做的是帧间预测,所以前面的函数先暂时不管了,挖个坑以后再填。直接从enc_pic看起。 enc_pic()    ...

CRR的博客 3187

快速学习Java中的广度优先和深度优先算法、动态规划和贪心技巧

这篇博客将重点介绍Java中最常见的搜索和遍历算法——广度优先搜索和深度优先搜索。除此以外,我们还将了解动态规划和贪心算法,并掌握它们在解决优化问题中的应用。如果你对于这些概念还不是很熟悉,那么这篇博客将会为你提供比较详尽的介绍和示例,帮助你轻松入门。

亮点菌 846

将外部电磁近场数据导入 ANSYS HFSS

本博客介绍了如何将电磁近场数据导入 ANSYS HFSS。用户可能需要导入字段,无论是通过分析计算、测量、由其他工具生成还是从提供商处接收的字段,并将其用作实际激励来执行不同类型的分析。以下是导入过程的简要概述,视频链接中提供了完整的演示。为了定义简单基元近场源,HFSS 使用两种外部数据文件。首先,实际位置/字段数据以 .nfd 格式存储。其次,Ansys Near field Descriptor 文件(.and 文件)存储 .nfd 数据的一般几何信息和路径。

jkh920184196的博客 2323

GStreamer —— 2.1、Windows搭建GStreamer环境,Qt加载GStreamer库后运行 - “教程1:Hello world!“(附:完整源码)

GStreamer —— 2、Windows搭建GStreamer环境,Qt加载GStreamer库后运行"教程1:Hello world!"

796

JAVA基础:图算法-深度优先搜索(DFS)和广度优先搜索(BFS)

JAVA基础:图算法-深度优先搜索(DFS)和广度优先搜索(BFS)

weixin_46619605的博客 1926

华为OD机试 - 打印机队列 - 优先队列(Python/JS/C/C++ 双机位C卷 200分)

这个问题要求模拟打印机的文件调度过程,关键在于正确处理每个打印机队列中的文件优先级和文件进入队列的顺序。优先级处理:每个文件有一个 1 到 10 的优先级,数字越大优先级越高,打印机应首先处理优先级最高的文件。在打印机 1 的队列中插入了 3 个文件,分别有不同的优先级,其中编号 3 的文件优先级最高,先被取出。因为打印的文件内容有轻重缓急之分,所以队列中的文件有1~10 不同的 优先级,其中数字越大优先级越高。在打印机 2 的队列中插入了 1 个文件,优先级为 1,因此它被首先取出。

学Java,找哪吒 1079

广度优先搜索算法及其MATLAB实现

摘要 广度优先搜索算法(又称宽度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。(来自百度百科) 算法思想 1.对图中的任...

爱音乐的程序员的博客 6641

基于Jeecgboot3.9.0的flowable7.2.0流程增加一个OA请假单功能例子(二)

基于Jeecgboot3.9.0的flowable7.2.0流程增加一个OA请假单功能例子(二)

宁波阿成的博客 198

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

广度优先搜索和深度优先搜索相关代码

广度优先搜索 类似于树的按层次遍历的过程,用到队列相关知识 首先从顶点v出发,依此访问其邻接点,访问完成后再从这些邻接点出发依此访问其邻接点(按顺序) 因为这些结点先访问,其邻接点亦先访问,所以可以用队列来存放已访问的结点。 深度优先搜索 有时候大拘泥于书上现成的代码不好 #include<stdio.h> #define MaxNum 100 typedef struct{ in...

qq_44646353的博客 217

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

《深入理解经典广度优先遍历算法》

广度优先遍历

博客网站地址: https://arsenova.xyz 我会将优快云上的博客重修一部分迁移到网站上。 文章会做同步更新,但我不会在这个糟糕的平台多待1秒。下面是我要说的话,save your time. keep going 1669

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

C++链表在图算法中作为邻接表实现的关键技术研究

通过阐述图的基本概念和链表数据结构特性,详细分析链表构建邻接表的原理与方法,深入研究基于邻接表实现的广度优先搜索(BFS)、深度优先搜索(DFS)等经典图算法,并对性能进行优化与分析,为图算法在实际场景中的高效应用提供理论支撑与实践指导。通过掌握构建邻接表关键技术和基于邻接表的图算法,利用优化策略提升性能,能高效解决各种图相关问题,推动图算法在多领域应用发展。邻接表是图的一种链式存储结构,为图中每个顶点建立一个单链表,链表中节点表示与该顶点相邻的顶点及边的信息(若边带权,还包含权值)。

wengang345的博客 300

【算法日记】广度优先算法

广度优先算法是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。广度优先搜索让你能够找出两样东西之间最短的距离。在学习这个算法...

diaoyucan2509的博客 186

深搜与广搜

深度优先搜索与广度优先搜索 深度优先搜索的思想是尽可能深的搜索,算法艺术与信息学竞赛一书中提到:随机搜索就像是在慌乱之中找东西,因为你并不知道东西在哪,广度优先搜索则像是你的眼镜掉在地上之 深度优先搜索 (DFS) 深度优先搜索属于图算法的一种,英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次;

My_Fresh_Start的博客 5733

bfs广度优先搜索(邻接矩阵+邻接表)

广度优先搜索算法: 邻接矩阵: #include <iostream> #include <bits/stdc++.h> #define maxn 10000 using namespace std; const int inf=99999; int e[maxn][maxn]; bool visit[maxn]; int m,n; void bfs(int u)//遍...

qq_44317766的博客 499

搞定技术面试-图算法相关问题(上)

图 图的基本表示 表示一个图有两种标准方法:图邻接表和图的邻接矩阵; 邻接矩阵就是用数组(二维)表示图。具体可以看下面例子。当然,这种情况很容易造成空间浪费,所以很多人进行空间优化,甚至是邻接表的方式。 邻接表咋是数组嵌套链表,这样会比邻接矩阵省不少空间,但对无向图来说,依旧会浪费一半的空间。 在本文中,使用 G=(V,E) 表示一个图,V表示顶点,E表示边。 图的常见概念 顶点=结点; 边...

ChaoQun 1972

dfs bfs java_图的搜索算法:BFS和DFS详解(Java实现)

图的搜索算法:BFS和DFS详解(Java实现)上一篇我们介绍了图的基本概念以及图的存储方式:邻接矩阵和邻接表;接下来我们将介绍一下有关图的基本的遍历算法,BFS(广度优先搜索遍历 )和DFS(深度优先搜索遍历 )这两种遍历方式。这里我们就以无向图来做示例:无向图G1DFS(深度优先遍历)深度优先搜索是从起始顶点开始,递归访问其所有邻近节点,比如A节点是其第一个邻近节点,而C节点又是A的一个邻近节...

weixin_39839478的博客 383

BFS(宽度优先搜索)的简单代码实现

#include<iostream> #include<queue> using namespace std; //广度优先搜索测试 //例: // 1 // / | \ // / | \ // 2 3---4 // | // | // 5 //step1:将存储图的方法称为图的*邻接矩阵存储法* // 通路用1表示,不通用-1表示,自身为0 .

理工大猪猪的博客 610

常见的算法技巧——图算法

这篇文章介绍了常见的算法技巧——图算法。

qq_45902301的博客 1509

图的dfs与bfs

看更多 思路简介 图的bfs极度类似树的层次遍历,用队列去实现。dfs则极度类似树的非递归遍历,用栈去实现。 代码 //-------------------我是DFS的开头------------------------------ void dfs_base_matrix_init(int** data,int size) { if(data == NULL || size &l...

赵阿 251
上一篇: zookeeper在docker中部署(单节点模式)
下一篇: 基础图算法:深度搜索优先(DFS)
F_Hello_World
博客等级 码龄11年 38粉丝 58原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值