【算法】广度优先遍历 (BFS)

这篇具有很好参考价值的文章主要介绍了【算法】广度优先遍历 (BFS)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.概述

(1)广度优先遍历 (Breadth First Search),又称宽度优先遍历,是最简便的图的搜索算法之一。

(2)已知图 G = (V, E) 和一个源顶点 start,宽度优先搜索以一种系统的方式探寻 G 的边,从而“发现” start 所能到达的所有顶点,并计算 start 到所有这些顶点的距离(最少边数),该算法同时能生成一棵根为 start 且包括所有可达顶点的广度优先树。对从 start 可达的任意顶点 v,广度优先树中从 start 到 v 的路径对应于图 G 中从 start 到 v 的最短路径,即包含最小边数的路径。该算法对有向图无向图同样适用。

(3)之所以称之为广度优先遍历,是因为算法自始至终一直通过已找到和未找到顶点之间的边界向外扩展,就是说,算法首先搜索和 start 距离为 k 的所有顶点,然后再去搜索和 start 距离为 k + 1 的其他顶点。

2.代码实现

(1)当使用邻接矩阵来表示图时,其代码实现如下:

class Solution {
    /*
    	adjMatrix 为邻接矩阵,adjMatrix[i][j] = 0 表示节点 i 和 j 之间没有边直接相连
    	start 为遍历的起点
	*/
    public void bfs(int[][] adjMatrix, int start) {
        // n 表示图中的节点数量,节点编号为 0 ~ n - 1
        int n = adjMatrix.length;
        //定义 visited 数组,防止对节点进行重复遍历
        boolean[] visited = new boolean[n];
        Queue<Integer> queue = new LinkedList<>();
        if (start < 0 || start > n - 1) {
            System.out.println("起点编号应为 [0, " + (n - 1) + "] 之间的整数!");
            return;
        }
        //起点入队
        queue.offer(start);
        //标记起点
        visited[start] = true;
        System.out.print(start + " ");
        while (!queue.isEmpty()) {
            int node = queue.poll();
            //将与节点 node 相连的节点加入到 queue 中
            for (int i = 0; i < n; i++) {
                if (adjMatrix[node][i] != 0 && !visited[i]) {
                    System.out.print(i + " ");
                    visited[i] = true;
                    queue.offer(i);
                }
            }
        }
    }
}

(2)当使用邻接表来表示图时,其代码实现如下:

class Solution {
   /*
    	adjList 为邻接表,adjList[i] 中存储与节点 i 相邻的节点
    	start 为遍历的起点
	*/
    public void bfs(List<Integer>[] adjList, int start) {
        // n 表示图中的节点数量,节点编号为 0 ~ n - 1
        int n = adjList.length;
        //定义 visited 数组,防止对节点进行重复遍历
        boolean[] visited = new boolean[n];
        Queue<Integer> queue = new LinkedList<>();
        if (start < 0 || start > n - 1) {
            System.out.println("起点编号应为 [0, " + (n - 1) + "] 之间的整数!");
            return;
        }
        //起点入队
        queue.offer(start);
        //标记起点
        visited[start] = true;
        System.out.print(start + " ");
        while (!queue.isEmpty()) {
            int node = queue.poll();
            //将与节点 node 相连的节点加入到 queue 中
            for (int nextNode : adjList[node]) {
                while (!visited[nextNode]) {
                    System.out.print(nextNode + " ");
                    visited[nextNode] = true;
                    queue.offer(nextNode);
                }
            }
        }
    }
}

(3)下面以图 G 为例来说明:

【算法】广度优先遍历 (BFS)

① 构造邻接矩阵:

int[][] adjMatrix = {
	        {0, 1, 1, 0, 1},
	        {1, 0, 0, 1, 1},
	        {1, 0, 0, 0, 1},
	        {0, 1, 0, 0, 1},
	        {1, 1, 1, 1, 0}
	};

② 构造邻接表:

int n = 5;
List<Integer>[] adjList = new ArrayList[n];
for (int i = 0; i < n; i++) {
    adjList[i] = new ArrayList<>();
}
adjList[0].add(1);
adjList[0].add(2);
adjList[0].add(4);
adjList[1].add(0);
adjList[1].add(3);
adjList[1].add(4);
adjList[2].add(0);
adjList[2].add(4);
adjList[3].add(1);
adjList[3].add(4);
adjList[4].add(0);
adjList[4].add(1);

如果 start = 2,那么遍历的节点依次为:

2 0 4 1 3

遍历过程如下图所示:
【算法】广度优先遍历 (BFS)

(4)无论是邻接表还是邻接矩阵的存储方式,BFS 算法都需要借助一个辅助队列 queue,n 个顶点均需入队一次,在最坏的情况下,空间复杂度为 O(|V|),而时间复杂度与图的存储方式有关:

  • 采用邻接矩阵存储方式时,查找每个顶点的邻接点所需的时间为O(|V|),故算法总的时间复杂度为 O(|V|2);
  • 采用邻接表存储方式时,每个顶点均需搜索一次(或入队一次),故时间复杂度为 O(|V|),在搜索任一顶点的邻接点时,每条边至少访问一次,故时间复杂度为 O(|E|),算法总的时间复杂度为 O(|V| + |E|);

3.应用

(1)除了对图进行遍历以外,BFS 在求解最短路径或者最短步数上有很多的应用。

(2)LeetCode 中的934.最短的桥这题便是对 BFS 的应用:

【算法】广度优先遍历 (BFS)

思路如下:
① 通过遍历找到数组 grid 中的 1 后进行广度优先搜索,此时可以得到第一座岛的位置集合,记为 island,并将其位置全部标记为 −1。
② 从 island 中的所有位置开始进行 BFS,当它们到达了任意的 1 时,即表示搜索到了第二个岛,搜索的层数就是答案。

代码实现如下:

class Solution {
    public int shortestBridge(int[][] grid) {
        int n = grid.length;
        // dirs 记录遍历的四个方向
        int[][] dirs = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
        List<int[]> island = new ArrayList<>();
        Queue<int[]> queue = new ArrayDeque<>();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1) {
                    queue.offer(new int[]{i, j});
                    grid[i][j] = -1;
                    while (!queue.isEmpty()) {
                        int[] land = queue.poll();
                        int x = land[0];
                        int y = land[1];
                        island.add(land);
                        for (int k = 0; k < 4; k++) {
                            int nextX = x + dirs[k][0];
                            int nextY = y + dirs[k][1];
                            if (nextX >= 0 && nextY >= 0 && nextX < n && nextY < n && grid[nextX][nextY] == 1) {
                                queue.offer(new int[]{nextX, nextY});
                                //标记 (nextX, nextY),表示已经访问过该点
                                grid[nextX][nextY] = -1;
                            }
                        }
                    }
                    /*
                    	(1) 此时已经找到了题目中描述的两座岛中的一座,并且组成岛的每块陆地的坐标位置都保存在 island 中。
						(2) 从 island 中的所有坐标位置开始进行 BFS,当它们达到了任意的 1 时,即表示搜索到了第二座岛,
							此时搜索的层数即为答案,在下面的代码中使用 step 来记录。
					*/
                    for (int[] land : island) {
                        queue.offer(land);
                    }
                    int step = 0;
                    while (!queue.isEmpty()) {
                        int size = queue.size();
                        for (int k = 0; k < size; k++) {
                            int[] land = queue.poll();
                            int x = land[0];
                            int y = land[1];
                            for (int d = 0; d < 4; d++) {
                                int nextX = x + dirs[d][0];
                                int nextY = y + dirs[d][1];
                                if (nextX >= 0 && nextY >= 0 && nextX < n && nextY < n) {
                                    if (grid[nextX][nextY] == 0) {
                                        queue.offer(new int[]{nextX, nextY});
                                        //标记 (nextX, nextY),表示已经访问过该点
                                        grid[nextX][nextY] = -1;
                                    } else if (grid[nextX][nextY] == 1) {
                                        return step;
                                    }
                                }
                            }
                        }
                        step++;
                    }
                }
            }
        }
        return 0;
    }
}

(3)大家可以去 LeetCode 上找相关的 BFS 的题目来练习,或者也可以直接查看LeetCode算法刷题目录(Java)这篇文章中的 BFS 章节。如果大家发现文章中的错误之处,可在评论区中指出。文章来源地址https://www.toymoban.com/news/detail-481297.html

到了这里,关于【算法】广度优先遍历 (BFS)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 图的遍历(广度优先遍历BFS,深度优先遍历DFS)

    目录 图的遍历概念: 图的广度优先遍历(BFS): 代码实现如下: 测试如下: 注意: 图的深度优先遍历(DFS): 代码实现如下: 测试如下: 总代码: 结语: 给定一个图G和其中任意一个顶点v0,从v0出发,沿着图中各边访问图中的所有顶点,且每个顶点仅被遍历一次。\\\"遍

    2024年02月21日
    浏览(54)
  • 【数据结构】图的遍历:广度优先(BFS),深度优先(DFS)

    目录 1、广度优先(BFS) 算法思想  广度优先生成树  知识树  代码实现  2、深度优先(DFS) 算法思想  深度优先生成树 知识树  代码实现           图的广度优先遍历(BFS)是一种遍历图的算法,其思想是从起始顶点开始遍历图,先访问起始顶点的所有直接邻居,然

    2024年02月04日
    浏览(63)
  • 【数据结构】广度优先遍历(BFS)模板及其讲解

    🎊专栏【数据结构】 🍔喜欢的诗句:更喜岷山千里雪 三军过后尽开颜。 🎆音乐分享【勋章】 大一同学小吉,欢迎并且感谢大家指出我的问题🥰 目录   🎁定义 🎁遍历方法  🎁根据题目来理解BFS 🏳️‍🌈走迷宫 🏳️‍🌈思路 🏳️‍🌈代码(BFS模板) 🏳️‍🌈分

    2024年02月06日
    浏览(41)
  • 对无向图进行邻接矩阵的转化,并且利用DFS(深度优先)和BFS(广度优先)算法进行遍历输出, 在邻接矩阵存储结构上,完成最小生成树的操作。

    目录 一 实验目的 二 实验内容及要求 实验内容: 实验要求: 三 实验过程及运行结果 一 算法设计思路 二 源程序代码 三、截图 四 调试情况、设计技巧及体会 1.掌握图的相关概念。 2.掌握用邻接矩阵和邻接表的方法描述图的存储结构。 3.掌握图的深度优先搜索和广度优

    2024年02月04日
    浏览(54)
  • 【数据结构】图的创建和深度(DFS)广度(BFS)优先遍历

    图是由顶点的有穷非空集合和顶点之间边的集合组成,通过表示为G(V,E),其中,G标示一个图, V是图G中 顶点的集合 , E是图G中 边的集合 。 图分为 无向图 和 有向图 无向图: 若顶点Vi到Vj之间的边没有方向,则称这条边为无向边(Edge),用序偶对(Vi,Vj)表示。 有向图: 若从

    2024年02月05日
    浏览(59)
  • 图的遍历——深度优先搜索(DFS)与广度优先搜索(BFS)(附带C语言源码)

    个人主页:【😊个人主页】 系列专栏:【❤️数据结构与算法】 学习名言:天子重英豪,文章教儿曹。万般皆下品,惟有读书高——《神童诗劝学》 第一章 ❤️ 学前知识 第二章 ❤️ 单向链表 第三章 ❤️ 递归 … 在此之前我们学习过了图的一些基本概念,如同在二叉树

    2024年02月06日
    浏览(65)
  • 数据结构实验6 :图的存储与遍历(邻接矩阵的深度优先遍历DFS和邻接表的广度优先遍历BFS)

    利用邻接矩阵存储无向图,并从0号顶点开始进行深度优先遍历。 输入第一行是两个整数n1 n2,其中n1表示顶点数(则顶点编号为0至n1-1),n2表示图中的边数。 之后有n2行输入,每行输入表示一条边,格式是“顶点1 顶点2”,把边插入图中。 例如: 4 4 0 1 1 3 0 3 0 2 先输出存储

    2024年02月09日
    浏览(63)
  • 数据结构第十六天(二叉树层序遍历/广度优先搜索(BFS)/队列使用)

    目录 前言 概述 接口 源码 测试函数 运行结果 往期精彩内容 从前的日色变得慢,车,马,邮件都慢,一生,只够爱一个人。 二叉树的层序遍历可以使用广度优先搜索(BFS)来实现。具体步骤如下: 创建一个队列 queue,并将根节点入队。 当队列不为空时,重复执行以下步骤:

    2024年02月22日
    浏览(36)
  • 深度优先搜索(DFS)和广度优先搜索(BFS)两种算法c++

    深度优先搜索(DFS)和广度优先搜索(BFS)是一种用于遍历或搜索树图的一种算法,在这个过程中保证图或数的每个结点被访问且仅被访问一次,再按照每个结点访问的顺序不同分为深搜和广搜。 本文只讨论这两种算法在搜索方面的应用! 深度优先搜索 ( Depth-First-Search,DFS )它 沿

    2024年02月13日
    浏览(47)
  • Python 算法基础篇:深度优先搜索( DFS )和广度优先搜索( BFS )

    深度优先搜索( DFS )和广度优先搜索( BFS )是两种常用的图遍历算法,用于在图中搜索目标节点或遍历图的所有节点。本篇博客将介绍 DFS 和 BFS 算法的基本概念,并通过实例代码演示它们的应用。 😃😄 ❤️ ❤️ ❤️ 深度优先搜索( DFS )是一种用于遍历或搜索图或树

    2024年02月07日
    浏览(65)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包