DFS and BFS

简介: DFS and BFS

两种实现都是基于邻接表


DFS(深度优先搜索)



深度优先遍历是一种优先走到底、无路可走再回头的遍历方式。具体地,从某个顶点出发,访问当前顶点的某个邻接顶点,直到走到尽头时返回,再继续走到尽头并返回,以此类推,直至所有顶点遍历完成。


image-20230425185250331.png


这种算法一般我们可以用递归实现 ,也可以用栈实现。同样的, 我们需要接著一个辅助数组来记录我们已经访问过的顶点。


算法实现


public class Graph {
    // 邻接表,key: 顶点,value:该顶点的所有邻接顶点
    Map<Vertex, List<Vertex>> adjList;
    /**
     * 初始化邻接表
     * @param edges 两顶点之间的边的关系, edges中的数代表顶点上的数
     */
    public Graph(Vertex[][] edges){
        this.adjList = new HashMap<>();
        //添加顶点
        for (Vertex[] edge  : edges){
            addVertex(edge[0]);
            addVertex(edge[1]);
            //添加边
            addAdjMat(edge[0],edge[1]);
        }
    }
    /**
     * 添加两个顶点之间的关系, 也就是添加边的关系
     * @param item0 顶点0
     * @param item1 顶点1
     */
    private void addAdjMat(Vertex item0, Vertex item1) {
        //首先判断两个顶点是否存在, 如果不存在就不能添加边的关系
        if (!adjList.containsKey(item0) || !adjList.containsKey(item1) || item0 == item1){
            throw new IndexOutOfBoundsException("其中一个顶点不存在!");
        }
        if (!adjList.get(item0).contains(item1)){
            adjList.get(item0).add(item1);
        }
           if (!adjList.get(item1).contains(item0)){
            adjList.get(item1).add(item0);
        }
    }
    /**
     * 添加点 ,并且需要将扩展顶点
     * @param item 顶点val
     */
    private void addVertex(Vertex item) {
        //先判断顶点是否存在
        if(adjList.containsKey(item)){
            return;
        }
        adjList.put(item,new ArrayList<>());
    }
    /**
     * 删除顶点 ,同时需要删除所有有关它的边的关系
     * @param val 顶点的所有边的关系
     */
    public void removeVertex(Vertex val){
        //先判断顶点是否存在
        if(!adjList.containsKey(val)){
            throw new IndexOutOfBoundsException("顶点不存在");
        }
        adjList.remove(val);
        //先遍历每个顶点,然后看他里面是否存在val顶点, 存在就删除
        for (Map.Entry<Vertex,List<Vertex>> item : adjList.entrySet()){
           item.getValue().remove(val);
        }
    }
    //todo 打印邻接表
    public void list(){
        for (Map.Entry<Vertex,List<Vertex>> item : adjList.entrySet()){
            System.out.print("key : " + item.getKey() + " value : ");
            List<Vertex> value = item.getValue();
            for (Vertex vertex  : value){
                System.out.print(vertex + "—>");
            }
            System.out.println();
        }
    }
    /**
     * 深度优先搜索
     * @param adjList 存储元素的邻接表
     * @param vertex 传入遍历的节点
     * @param visited 记录当前节点地日志数组
     */
       public static void DFS(Map<Vertex, List<Vertex>> adjList,Vertex vertex,int[] visited){
        visited[vertex.val] = 1;
        System.out.print(vertex + "\t");
        List<Vertex> vertices = adjList.get(vertex);
        Iterator<Vertex> iterator = vertices.iterator();
        while(iterator.hasNext()){
            Vertex v = iterator.next();
            if(visited[v.val] == 0){
                DFS(adjList,v,visited);
            }
        }
    }
    public static void main(String[] args) {
        Vertex vertex1 = new Vertex(1);
        Vertex vertex3 = new Vertex(3);
        Vertex vertex2 = new Vertex(2);
        Vertex vertex5 = new Vertex(0);
        Vertex vertex4 = new Vertex(4);
        Vertex[][] vertices = new Vertex[][]{
                {vertex1,vertex3},
                {vertex3,vertex1},
                {vertex2,vertex3},
                {vertex5,vertex1},
                {vertex4,vertex2},
        };
        Graph graph = new Graph(vertices);
        graph.addAdjMat(vertex1, vertex5);
        graph.addAdjMat(vertex3, vertex2);
        graph.addAdjMat(vertex2, vertex5);
        graph.addAdjMat(vertex2, vertex4);
        graph.addAdjMat(vertex5, vertex2);
        graph.addAdjMat(vertex5, vertex4);
        graph.addAdjMat(vertex4, vertex5);
        graph.list();
        BFS(graph.adjList,vertex1);
        System.out.println();
        DFS(graph.adjList,vertex1);
    }
}


BFS(广度优先搜索)



广度优先遍历是一种由近及远的遍历方式,从距离最近的顶点开始访问,并一层层向外扩张。具体来说,从某个顶点出发,先遍历该顶点的所有邻接顶点,然后遍历下一个顶点的所有邻接顶点,以此类推,直至所有顶点访问完毕。

image-20230425190438910.png



广度优先搜索,我们使用的是队列来实现。先进先出 ,我们先将一个顶点加入队列, 然后当他出队列的时候,再将他身边的顶点加入队列。 ,循环往复,直到队列为空, 那么就是将所有的顶点遍历完成。


同时,我们这里也需要一个辅助数组, 用来记录已经加入队列遍历过的顶点。


算法实现


package tu;
import org.omg.CORBA.MARSHAL;
import java.util.*;
/**
 * 基于邻接表实现图
 * 将顶点用顶点类Vertex 进行封装
 */
public class Graph {
    // 邻接表,key: 顶点,value:该顶点的所有邻接顶点
    Map<Vertex, List<Vertex>> adjList;
    /**
     * 初始化邻接表
     * @param edges 两顶点之间的边的关系, edges中的数代表顶点上的数
     */
    public Graph(Vertex[][] edges){
        this.adjList = new HashMap<>();
        //添加顶点
        for (Vertex[] edge  : edges){
            addVertex(edge[0]);
            addVertex(edge[1]);
            //添加边
            addAdjMat(edge[0],edge[1]);
        }
    }
    /**
     * 添加两个顶点之间的关系, 也就是添加边的关系
     * @param item0 顶点0
     * @param item1 顶点1
     */
    private void addAdjMat(Vertex item0, Vertex item1) {
        //首先判断两个顶点是否存在, 如果不存在就不能添加边的关系
        if (!adjList.containsKey(item0) || !adjList.containsKey(item1) || item0 == item1){
            throw new IndexOutOfBoundsException("其中一个顶点不存在!");
        }
        if (!adjList.get(item0).contains(item1)){
            adjList.get(item0).add(item1);
        }
           if (!adjList.get(item1).contains(item0)){
            adjList.get(item1).add(item0);
        }
    }
    /**
     * 添加点 ,并且需要将扩展顶点
     * @param item 顶点val
     */
    private void addVertex(Vertex item) {
        //先判断顶点是否存在
        if(adjList.containsKey(item)){
            return;
        }
        adjList.put(item,new ArrayList<>());
    }
    /**
     * 删除顶点 ,同时需要删除所有有关它的边的关系
     * @param val 顶点的所有边的关系
     */
    public void removeVertex(Vertex val){
        //先判断顶点是否存在
        if(!adjList.containsKey(val)){
            throw new IndexOutOfBoundsException("顶点不存在");
        }
        adjList.remove(val);
        //先遍历每个顶点,然后看他里面是否存在val顶点, 存在就删除
        for (Map.Entry<Vertex,List<Vertex>> item : adjList.entrySet()){
           item.getValue().remove(val);
        }
    }
    //todo 打印邻接表
    public void list(){
        for (Map.Entry<Vertex,List<Vertex>> item : adjList.entrySet()){
            System.out.print("key : " + item.getKey() + " value : ");
            List<Vertex> value = item.getValue();
            for (Vertex vertex  : value){
                System.out.print(vertex + "—>");
            }
            System.out.println();
        }
    }
    /**
     * 实现广度优先搜索 暂时规定
     * @param adjList 存储元素的邻接表
     * @param vertex 传入遍历的头节点
     */
    public static void BFS(Map<Vertex, List<Vertex>> adjList,Vertex vertex){
        Deque<Vertex> deque = new LinkedList<>();
        int size = adjList.size();
        int[] visited = new int[size];
        Arrays.fill(visited,0);
        //将入队列元素标记。 然后让元素入队列
        visited[vertex.val] = 1;
        deque.push(vertex);
        while (!deque.isEmpty()){
            Vertex poll = deque.poll();
            /*处理方法 */
            System.out.print(poll + "\t");
            List<Vertex> vertices = adjList.get(poll);
            for (Vertex v : vertices){
                if (visited[v.val] != 1){
                    deque.push(v);
                    visited[v.val] = 1;
                }
            }
        }
    }
    public static void main(String[] args) {
        Vertex vertex1 = new Vertex(1);
        Vertex vertex3 = new Vertex(3);
        Vertex vertex2 = new Vertex(2);
        Vertex vertex5 = new Vertex(0);
        Vertex vertex4 = new Vertex(4);
        Vertex[][] vertices = new Vertex[][]{
                {vertex1,vertex3},
                {vertex3,vertex1},
                {vertex2,vertex3},
                {vertex5,vertex1},
                {vertex4,vertex2},
        };
        Graph graph = new Graph(vertices);
        graph.addAdjMat(vertex1, vertex5);
        graph.addAdjMat(vertex3, vertex2);
        graph.addAdjMat(vertex2, vertex5);
        graph.addAdjMat(vertex2, vertex4);
        graph.addAdjMat(vertex5, vertex2);
        graph.addAdjMat(vertex5, vertex4);
        graph.addAdjMat(vertex4, vertex5);
        graph.list();
        BFS(graph.adjList,vertex1);
        System.out.println();
        DFS(graph.adjList,vertex1);
    }
}


运行结果



image-20230425113904576.png



目录
相关文章
|
5月前
|
C++
|
6月前
|
算法
深度优先搜索(DFS)的基础理解与实现
深度优先搜索(DFS)的基础理解与实现
78 0
|
存储 前端开发 算法
深度优先搜索(DFS)和广度优先搜索(BFS)
深度优先搜索(DFS)和广度优先搜索(BFS)
120 0
DFS(深度优先搜索)和BFS(宽度优先搜索)
DFS(深度优先搜索)和BFS(宽度优先搜索)
79 0
|
算法
DFS深度优先搜索
DFS深度优先搜索
|
存储 算法 PHP
深度优先搜索(DFS)
深度优先搜索(DFS)
236 0
深度优先搜索(DFS)
|
算法
【和zqy学算法】Day1:DFS与BFS
【和zqy学算法】Day1:DFS与BFS
150 0
|
算法 Java Python
【算法题解】 Day6 BFS | DFS
今天的算法是 「BFS | DFS」 相关,“算法题解系列文章旨在精选重点与易错的算法题,总结常见的算法思路与可能出现的错误,以实战习题的形式理解算法,使用算法。”
101 0
|
算法 Java 索引
【算法题解】 Day10 BFS | DFS
今天的算法是 「BFS | DFS」 相关,“算法题解系列文章旨在精选重点与易错的算法题,总结常见的算法思路与可能出现的错误,以实战习题的形式理解算法,使用算法。”
101 0
|
算法
【29. DFS深度优先】
# 概述 - DFS:深度优先遍历,从一条路径走到叶节点,然后回溯,继续遍历(不撞南墙不回头) - BFS:广度优先遍历,从根节点,一层一层的遍历,每一层把所有的节点都遍历完成。 ## 递归思想 - 递归在于不断调用自己的函数,层层深入,直到遇到递归终止条件后层层回溯,其思想与dfs的思想不谋而合;因此,可以使用递归来实现dfs。 - 递归的进入比较容易理解,但是递归的回溯是在计算机底层执行的,我们无法看到。因此这是理解递归的唯一一个难点。
134 0
【29. DFS深度优先】