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

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

目录

图的遍历概念:

图的广度优先遍历(BFS):

代码实现如下:

测试如下:

注意:

图的深度优先遍历(DFS):

代码实现如下:

测试如下:

总代码:

结语:


图的遍历概念:

给定一个图G和其中任意一个顶点v0,从v0出发,沿着图中各边访问图中的所有顶点,且每个顶点仅被遍历一次。"遍历"即对结点进行某种操作的意思。由于考试大多考邻接矩阵(GraphByMatrix),故下面的遍历都是用邻接矩阵(GraphByMatrix),不是邻接表(GraphByNode)。

图的广度优先遍历(BFS):

广度优先遍历类似于我们前面所学二叉树的层序遍历,一层一层的走,故可以使用队列来模拟实现。

比如:现在有三个抽屉(每个抽屉包含一个红色盒子,红色盒子中又包含一个绿色盒子),所需东西在那个抽屉不清楚,现在要将其找到,广度优先遍历的做法是:

(1)先将三个抽屉打开,在最外层找一遍。

(2)将每个抽屉中红色的盒子打开,再找一遍。

(3)最后将红色盒子中绿色盒子打开,再找一遍。

直到找完所有的盒子,注意:每个盒子只能找一次,不能重复找。

例如下图:

图的遍历(广度优先遍历BFS,深度优先遍历DFS),数据结构,算法,算法,数据结构,dfs,bfs,java,深度优先,广度优先

该图的广度优先遍历过程如下:

故其广度优先遍历的结果为:ABCDEFGHI。

图的遍历(广度优先遍历BFS,深度优先遍历DFS),数据结构,算法,算法,数据结构,dfs,bfs,java,深度优先,广度优先

代码实现如下:

1、初始化一个布尔类型数组visited,默认所有顶点都没有被遍历到。

2、获取当前开始的顶点V 的下标。

3、定义一个队列,存储当前需要遍历的顶点的下标。

4、取出当前队列的头部。

5、把当前的顶点的这一行都放到队列。

由于getIndexOfV,arrayV,matrix在上一篇文章中已经非常详细的描述过,故这里我只解释其作用,如若需要源码和更加详细的解释请友友前往:图的存储结构 

(1)geiIndexOfV 获取顶点元素在其数组中的下标 。

(2)arrayV 顶点元素的一维数组。

(3)matrix 利用matrix二维数组来存储顶点之间边的权重。

/**
     * 广度优先遍历
     * @param v
     */
    public void bfs(char v){
        //1、初始化一个布尔类型数组,默认所有顶点都没有被遍历到
        boolean[] visited = new boolean[arrayV.length];
        //2、获取当前开始的顶点V的下标
        int index = getIndexOfV(v);
        //3、定义一个队列,存储当前需要遍历的顶点的下标
        Queue<Integer> qu = new LinkedList<>();
        qu.offer(index);//起点放进来
        while(!qu.isEmpty()){
            //4、取出当前队列的头部
            int top = qu.poll();
            System.out.print(arrayV[top]+":"+"-> ");
            visited[top] = true;
            //5、把当前的顶点的这一行都放到队列
            for(int i = 0;i < arrayV.length;i++){
                //如果这一行的i下标不等于MAX_VALUE,并且也没有被访问过
                if(matrix[top][i] != Integer.MAX_VALUE && visited[i] == false){
                    qu.offer(i);
                    //注意,防止重复打印
                    visited[i] = true;
                }
            }
        }
        System.out.println("null");
    }

测试如下:

测试代码均围绕下图进行:

图的遍历(广度优先遍历BFS,深度优先遍历DFS),数据结构,算法,算法,数据结构,dfs,bfs,java,深度优先,广度优先

图的遍历(广度优先遍历BFS,深度优先遍历DFS),数据结构,算法,算法,数据结构,dfs,bfs,java,深度优先,广度优先

遍历结果为BACD显然符合我们的预期。 

注意:

下面话红线的地方不能省去。

图的遍历(广度优先遍历BFS,深度优先遍历DFS),数据结构,算法,算法,数据结构,dfs,bfs,java,深度优先,广度优先

如若省去会发生重复遍历例如:

图的遍历(广度优先遍历BFS,深度优先遍历DFS),数据结构,算法,算法,数据结构,dfs,bfs,java,深度优先,广度优先发生了DD的重复打印。

那为什么会发生重复打印呢?这是因为在C出队时,D已经在队列中了但是其还是false,故C出队会再次把D入队,这样就会重复打印。具体过程如下动图:

图的遍历(广度优先遍历BFS,深度优先遍历DFS),数据结构,算法,算法,数据结构,dfs,bfs,java,深度优先,广度优先

解决方法:在入队时一起把元素对应下标的visited数组设置为false。

为了方便友友调试下面将测试代码给出:

public static void main(String[] args) {
        GraphByMatrix graph = new GraphByMatrix(4,true);
        char[] array = {'A','B','C','D'};
        graph.initArrayV(array);
        graph.addEdge('A','B',1);
        graph.addEdge('A','D',1);
        graph.addEdge('B','A',1);
        graph.addEdge('B','C',1);
        graph.addEdge('C','B',1);
        graph.addEdge('C','D',1);
        graph.addEdge('D','A',1);
        graph.addEdge('D','C',1);
        graph.bfs('B');
    }

图的深度优先遍历(DFS):

图的深度优先遍历类似于前面所学二叉树的前序遍历,有路就走,走完没路了再回退,使用递归来实现。

比如:现在有三个抽屉(每个抽屉包含一个红色盒子,红色盒子中又包含一个绿色盒子),所需东西在那个抽屉不清楚,现在要将其找到,深度优先遍历的做法是:

(1)先将第一个抽屉打开,在最外层找一遍。

(2)将第一个抽屉中红色的盒子打开,在红色箱子里找一遍。

(3)将红色盒子中绿色盒子打开,在绿箱子里找一遍。

(4)递归查找剩余两个箱子。

深度优先遍历:将一个抽屉一次性遍历完(包括该抽屉中包含的小盒子),再去递归遍历其它盒子。

其过程如图所示:

图的遍历(广度优先遍历BFS,深度优先遍历DFS),数据结构,算法,算法,数据结构,dfs,bfs,java,深度优先,广度优先

其深度优先遍历结果为:ABEGCFDHI。

代码实现如下:

实现一个方法dfschild来进行递归,为什么不用dfs直接递归呢?这是因为如果直接把dfs递归哪visited会一直被开辟,堆上的内存占用太大,要把visited设置在dfs外面才行。

部分流程和前面所说的广度优先遍历类似,关于getIndexOfV,arrayV,matrix在广度优先遍历那已解释故这里不再过多描述。

 /**
     * 给定顶点,从顶点处开始进行深度优先遍历
     * @param v
     */
    public void dfs(char v){
        //1、初始化一个布尔类型数组,默认所有顶点都没有被遍历到
        boolean[] visited = new boolean[arrayV.length];
        //2、获取当前开始的顶点V 的下标
        int index = getIndexOfV(v);
        //3、开始从index位置进行深度遍历
        dfsChild(index,visited);
        System.out.print("null");
    }
    /**
     * 从index位置开始深度优先遍历
     * @param index
     * @param visited
     */
    private void dfsChild(int index,boolean[] visited){
        System.out.print(arrayV[index]+":"+"-> ");
        visited[index] = true;
        //当前index位置的,所有的连接点都在这一行
        for(int i = 0;i < arrayV.length;i++){
            //如果这一行的i下标不等于0,并且也没有被访问过
            if(matrix[index][i] != Integer.MAX_VALUE && visited[i] == false){
                dfsChild(i,visited);
            }
        }
    }

测试如下:

遍历结果为:BADC显然符合我们的预期。

图的遍历(广度优先遍历BFS,深度优先遍历DFS),数据结构,算法,算法,数据结构,dfs,bfs,java,深度优先,广度优先

总代码:

import java.sql.SQLOutput;
import java.util.Arrays;
import java.util.Queue;
import java.util.LinkedList;
public class GraphByMatrix {
    private char[] arrayV;//存放顶点·
    private int[][] matrix;//存放边
    private boolean isDirect;//是否是有向图
    public GraphByMatrix(int size,boolean isDirect){
        arrayV = new char[size];
        matrix = new int[size][size];
        for(int i = 0;i < size;i++){
            Arrays.fill(matrix[i],Integer.MAX_VALUE);
        }
        this.isDirect = isDirect;
    }
    /**
     * 初始化
     * @param array 顶点集合
     */
    public void initArrayV(char[] array){
        for(int i = 0;i < array.length;i++){
            arrayV[i] = array[i];
        }
    }

    /**
     *
     * @param v1 起始
     * @param v2 终点
     * @param weight 权值
     */
    public void addEdge(char v1,char v2,int weight){
        int index1 = getIndexOfV(v1);
        int index2 = getIndexOfV(v2);
        matrix[index1][index2] = weight;
        if(!isDirect){
            matrix[index2][index1] = weight;
        }
    }

    /**
     * 获取顶点元素在其数组中的下标
     * @param v
     * @return
     */
    public int getIndexOfV(char v){
        for(int i = 0;i < arrayV.length;i++){
            if(v == arrayV[i]){
                return i;
            }
        }
        return -1;
    }

    /**
     * 获取顶点的度
     * @param v
     * @return
     */
    public int getDevOfV(char v){
        int indexV = getIndexOfV(v);
        int count = 0;
        for(int i = 0;i < arrayV.length;i++){
            if(matrix[indexV][i] != Integer.MAX_VALUE){
                count++;
            }
        }
        if(isDirect){
            for(int i = 0;i < arrayV.length;i++){
                if(matrix[i][indexV] != Integer.MAX_VALUE){
                    count++;
                }
            }
        }
        return count;
    }
    public void printGraph(){
        for(int i = 0;i < arrayV.length;i++){
            System.out.print(arrayV[i] + " ");
        }
        System.out.println();
        for(int i = 0;i < matrix.length;i++){
            for(int j = 0;j < matrix[i].length;j++){
                if(matrix[i][j] == Integer.MAX_VALUE) {
                    System.out.print("∞ ");
                }else {
                    System.out.print(matrix[i][j]+" ");
                }
            }
            System.out.println();
        }
    }
    //广度优先遍历

    /**
     * 广度优先遍历
     * @param v
     */
    public void bfs(char v){
        //1、初始化一个布尔类型数组,默认所有顶点都没有被遍历到
        boolean[] visited = new boolean[arrayV.length];
        //2、获取当前开始的顶点V的下标
        int index = getIndexOfV(v);
        //3、定义一个队列,存储当前需要遍历的顶点的下标
        Queue<Integer> qu = new LinkedList<>();
        qu.offer(index);//起点放进来
        while(!qu.isEmpty()){
            //4、取出当前队列的头部
            int top = qu.poll();
            System.out.print(arrayV[top]+":"+"-> ");
            visited[top] = true;
            //5、把当前的顶点的这一行都放到队列
            for(int i = 0;i < arrayV.length;i++){
                //如果这一行的i下标不等于MAX_VALUE,并且也没有被访问过
                if(matrix[top][i] != Integer.MAX_VALUE && visited[i] == false){
                    qu.offer(i);
                    //注意,防止重复打印
//                    visited[i] = true;
                }
            }
        }
        System.out.println("null");
    }
    //图的深度优先遍历

    /**
     * 给定顶点,从顶点处开始进行深度优先遍历
     * @param v
     */
    public void dfs(char v){
        //1、初始化一个布尔类型数组,默认所有顶点都没有被遍历到
        boolean[] visited = new boolean[arrayV.length];
        //2、获取当前开始的顶点V 的下标
        int index = getIndexOfV(v);
        //3、开始从index位置进行深度遍历
        dfsChild(index,visited);
        System.out.print("null");
    }
    /**
     * 从index位置开始深度优先遍历
     * @param index
     * @param visited
     */
    private void dfsChild(int index,boolean[] visited){
        System.out.print(arrayV[index]+":"+"-> ");
        visited[index] = true;
        //当前index位置的,所有的连接点都在这一行
        for(int i = 0;i < arrayV.length;i++){
            //如果这一行的i下标不等于0,并且也没有被访问过
            if(matrix[index][i] != Integer.MAX_VALUE && visited[i] == false){
                dfsChild(i,visited);
            }
        }
    }
}

结语:

其实写博客不仅仅是为了教大家,同时这也有利于我巩固自己的知识点,和一个学习的总结,由于作者水平有限,对文章有任何问题的还请指出,接受大家的批评,让我改进,如果大家有所收获的话还请不要吝啬你们的点赞收藏和关注,这可以激励我写出更加优秀的文章。

图的遍历(广度优先遍历BFS,深度优先遍历DFS),数据结构,算法,算法,数据结构,dfs,bfs,java,深度优先,广度优先文章来源地址https://www.toymoban.com/news/detail-832725.html

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

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

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

相关文章

  • 图的遍历(搜索)算法(深度优先算法DFS和广度优先算法BFS)

    从图的某个顶点出发访问遍图中所有顶点,且每个顶点仅被访问一次。(连通图与非连通图) 1、访问指定的起始顶点; 2、若当前访问的顶点的邻接顶点有未被访问的,则任选一个访问之;反之,退回到最近访问过的顶点;直到与起始顶点相通的全部顶点都访问完毕; 3、若

    2024年01月17日
    浏览(33)
  • 【数据结构】图的创建(邻接矩阵,邻接表)以及深度广度遍历(BFS,DFS)

    图是由顶点集合及顶点间的关系组成的一种数据结构:G = (V, E),其中: 顶点集合V = {x|x属于某个数据对象集}是有穷非空集合; E = {(x,y)|x,y属于V}或者E = {x, y|x,y属于V Path(x, y)}是顶点间关系的有穷集合,也叫 做边的集合。 完全图:在有n个顶点的无向图中,若有n * (n-1)/2条边,

    2024年02月04日
    浏览(31)
  • 数据结构上机实验——图的实现(以无向邻接表为例)、图的深度优先搜索(DFS)、图的广度优先搜索(BFS)

      图采用邻接表存储结构,编程实现图的深度优先搜索和广度优先搜索算法。              2.1创建图 2.1.1定义图的顶点、边及类定义   我们定义一个 邻接表类(ALGraph) 。这里实现一些基础的数据结构。要注意结构体的嵌套。    Edge: 用于表示图中的边

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

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

    2024年02月06日
    浏览(47)
  • 大话数据结构-图的深度优先遍历和广度优先遍历

      图的遍历分为深度优先遍历和广度优先遍历两种。   深度优先遍历(Depth First Search),也称为深度优先搜索,简称DFS,深度优先遍历,是指从某一个顶点开始,按照一定的规则,访问并记录下一个未访问顶点。对于非连通图,则是按连通分量,采用同一规则进行深度优

    2024年02月04日
    浏览(44)
  • (超详细)C++图的深度优先遍历、广度优先遍历(数据结构)

            根据下图,编写代码实现图的深度优先遍历和广度优先遍历。          按照英文字母顺序,以邻接表为存储结构,实现图的深度优先和广度优先遍历。遍历的顺序从顶点a开始。 以用户指定的结点为起点,分别输出每种遍历下的结点访问序列。   (1)从顶点a,

    2024年02月08日
    浏览(47)
  • 【数据结构与算法】图的深度优先和广度优先遍历

    😊😊作者简介😊😊 : 大家好,我是南瓜籽,一个在校大二学生,我将会持续分享Java相关知识。 🎉🎉个人主页🎉🎉 : 南瓜籽的主页 ✨✨座右铭✨✨ : 坚持到底,决不放弃,是成功的保证,只要你不放弃,你就有机会,只要放弃的人,他肯定是不会成功的人。 图是一

    2024年02月02日
    浏览(46)
  • 【数据结构与算法】搜索算法(深度优先搜索 DFS和广度优先搜索 BFS)以及典型算法例题

    【数据结构与算法】系列文章链接: 【数据结构与算法】递推法和递归法解题(递归递推算法典型例题) 【数据结构与算法】系列文章链接: 【数据结构与算法】C++的STL模板(迭代器iterator、容器vector、队列queue、集合set、映射map)以及算法例题 【数据结构与算法】系列文章链

    2024年04月13日
    浏览(33)
  • 基于邻接矩阵的有向图的广度优先遍历(BFS)和深度优先遍历(DFS)算法

    概念: 广度优先遍历算法是图的另一种基本遍历算法,其基本思想是尽最大程度辐射能够覆盖的节点,并对其进行访问。 以迷宫为例,广度优先搜索则可以想象成一组人一起朝不同的方向走迷宫,当出现新的未走过的路的时候,可以理解成一个人有分身术,继续从不同的方

    2024年02月06日
    浏览(45)
  • 数据结构学习笔记——图的遍历算法(深度优先搜索和广度优先搜索)

    图的遍历指从图中某一顶点出发(任意一个顶点都可以作为访问的起始顶点),按照某种遍历方法,对图中所有的顶点访问一次且只访问一次。图与树不一样,其中一个顶点可能与多个顶点相连,所以需记录已访问过的顶点,当访问一个顶点后,考虑如何选取下一个要访问的

    2024年02月05日
    浏览(37)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包