图的BFS和DFS

栏目: 数据库 · 发布时间: 5年前

内容简介:图的遍历对于图这类题目来说非常重要,但是图的实现又非常的难。在这里我介绍下图的广度优先遍历和深度优先遍历,讲一下其中的算法思想。邻接矩阵表示:图的邻接矩阵存储结构定义如下:

图的遍历对于图这类题目来说非常重要,但是图的实现又非常的难。在这里我介绍下图的广度优先遍历和深度优先遍历,讲一下其中的算法思想。

1.图的存储结构

邻接矩阵表示:

图的BFS和DFS

图的邻接矩阵存储结构定义如下:

int n;
    boolean[][] a;
    Node(int n){
        this.n=n;
        a = new boolean[n][n];
    }
    void addEdge(int i, int j) {
        a[i][j] = true;
    }
    void removeEdge(int i, int j) {
        a[i][j] = false;
    }
    boolean hasEdge(int i, int j) {
        return a[i][j];
    }
复制代码

邻接矩阵表示法的时间复杂度为O(n^2),空间复杂度也是O(n^2)。n代表图中顶点的个数。

邻接表表示:

图的BFS和DFS

图的邻接表存储结构定义如下:

//顶点的数量
    private int V;
    //邻接表-数组类型的链表
    private LinkedList<Integer> adj[];

    //构造一个图
    DepthFirstSearch(int  v){
        V = v;
        //数组链表
        adj = new LinkedList[v];
        for (int i = 0; i < v; i++) {
            adj[i]=new LinkedList();
        }
    }

    //加入与顶点v相连的边v-w
    void addEdge(int v,int w){
        adj[v].add(w);
    }
复制代码

时间复杂度为:O(V + E)其中V是图中顶点的数量,E是图中边的数量 。

还是看以前的书比较有亲和感!

2.广度优先遍历(Breadth-First-Search,BFS)

广度优先遍历类似与二叉树的层序遍历。它是一种分层的查找过程,每向前走一步能访问一批顶点,不像深度优先遍历那样有往回退的情况,因此它不是一个递归的算法。 为了实现逐层的访问,算法必须借助一个辅助队列,以记忆正在访问顶点的下一层顶点。

package com.zhoujian.solutions.dataStructure.graph;
import java.util.*;
/**
 * @author zhoujian123@hotmail.com 2018/4/26 10:28
 * 图的广度优先遍历----借助队列
 * 广度优先遍历类似于二叉树的层序遍历
 * 图是用邻接表来存储(对于稀疏图来说,邻接表比较合适)
 * 时间复杂度:O(V+E),其中V是图中顶点的数量,E是图中边的数量
 */
public class BreadthFirstSerch {
    private int V; //顶点
    private LinkedList<Integer> adj[]; //领接表
    //构造器,利用链表。v是顶点的个数
    BreadthFirstSerch(int v){
        V=v;
        adj = new LinkedList[v];
        for (int i = 0; i <v; i++) {
            adj[i]=new LinkedList();
        }
    }
    //加入一条边到图中
    void addEdge(int v,int w){
        adj[v].add(w);
    }
    //从给定的顶点开始遍历
    void BFS(int s){
        //默认将所有的顶点设置为未被访问(false)
        boolean visited[] = new boolean[V];
        //创建一个队列
        LinkedList<Integer> queue = new LinkedList<Integer>();
        //把当前顶点设置为已访问并且入队
        visited[s] = true;
        queue.add(s);
        while (queue.size()!=0){
            //出队并打印出来
            s=queue.poll();
            System.out.println(s+"");
            //获取与s相关联的全部的顶点,如果邻接的点未被访问,则设置为已被访问且入队
            //i是一种list列表的迭代器,用于存储相邻节点的列表
            ListIterator<Integer> i = adj[s].listIterator();
            while (i.hasNext()){
                int n = i.next();
                if (!visited[n]){
                    visited[n]=true;
                    queue.add(n);
                }
            }
        }
    }

    public static void main(String[] args) {
        BreadthFirstSerch g = new BreadthFirstSerch(4);
        g.addEdge(0,1);
        g.addEdge(0,2);
        g.addEdge(1,2);
        g.addEdge(2,0);
        g.addEdge(2,3);
        g.addEdge(3,3);
        //这个函数只能从指定顶点开始遍历。要是打印所有顶点,可以需要修改BFS函数,逐个从所有节点开始遍历
        System.out.println("广度优先遍历从0开始遍历");
        g.BFS(0);
        System.out.println("广度优先遍历从1开始遍历");
        g.BFS(1);
        System.out.println("广度优先遍历从2开始遍历");
        g.BFS(2);
        System.out.println("广度优先遍历从3开始遍历");
        g.BFS(3);
    }

}

复制代码
图的BFS和DFS

3.深度优先遍历(Depath-First-Search,DFS)

深度优先遍历类似于树的先序遍历。DFS算法是一个递归的算法,需要借助一个递归的工作栈,故它的空间复杂度为O(V)。总的时间复杂度为O(V+E)。

package com.zhoujian.solutions.dataStructure.graph;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
/**
 * @author zhoujian123@hotmail.com 2018/4/25 21:19
 * 图的深度优先遍历:需要借助栈
 * 深度优先遍历类似于二叉树的先序遍历
 * 使用邻接表表示
 * 时间复杂度:当以领接表表示时,查找所有顶点的邻接点所需为O(V),然后每条边至少访问一次所需时间为O(E),
 * 总的时间复杂度为O(V+E)
 *
 */
public class DepthFirstSearch {

    //顶点的数量
    private int V;
    //邻接表-数组类型的链表
    private LinkedList<Integer> adj[];

    //构造一个图
    DepthFirstSearch(int  v){
        V = v;
        //数组链表
        adj = new LinkedList[v];
        for (int i = 0; i < v; i++) {
            adj[i]=new LinkedList();
        }
    }

    //加入与顶点v相连的边v-w
    void addEdge(int v,int w){
        adj[v].add(w);
    }
    /**
     * 从顶点v开始深度遍历
     * @param v 顶点v
     * @param visited 访问标识符
     */
    void DFSUtil(int v,boolean visited[]){

        //把当前节点设置为被访问并打印出来
        visited[v]=true;
        System.out.println(v+" ");

        ListIterator<Integer> i = adj[v].listIterator();
        while (i.hasNext()){
            //返回与v相邻的节点
            Integer n = i.next();
            if (!visited[n]){
                DFSUtil(n,visited);
            }
        }

    }

    void DFS(int v){
        //初始化所有顶点并默认为false(数组)
        boolean[] visited = new boolean[V];
        DFSUtil(v,visited);
    }

    public static void main(String[] args) {
        DepthFirstSearch g = new DepthFirstSearch(4);
        g.addEdge(0,1);
        g.addEdge(0,2);
        g.addEdge(1,2);
        g.addEdge(2,0);
        g.addEdge(2,3);
        g.addEdge(3,3);
        System.out.println("深度优先遍历从顶点2开始");
        g.DFS(2);
    }
}
复制代码
图的BFS和DFS

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

启示录

启示录

[美] Marty Cagan / 七印部落 / 华中科技大学出版社 / 2011-5 / 36.00元

为什么市场上那么多软件产品无人问津,成功的产品凤毛麟角?怎样发掘有价值的产品?拿什么说服开发团队接受你的产品设计?如何将敏捷方法融入产品开发?过去二十多年,Marty Cagan作为高级产品经理人为多家一流企业工作过,包括惠普、网景、美国在线、eBay。他亲历了个人电脑 、互联网、 电子商务的起落沉浮。《启示录:打造用户喜爱的产品》从人员、流程、产品三个角度介绍了现代软件(互联网)产品管理的实践经......一起来看看 《启示录》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具