算法:图的 "深度优先搜索" 和 "广度优先搜索" 的Java简单实现

22 篇文章 1 订阅
5 篇文章 0 订阅

算法一般跟数据结构是联系在一起的,数据关系一般有一对一、一对多、多对多。其中,一对一可以理解为线性表,如数组和链表这些;一对多可以理解为树,比如二叉树,一个根节点对两个子节点;多对多则可以理解为图,比如接下来提供的范例:
在这里插入图片描述
上面就是图(graph)的一个示例,A对应C和D,而D对应A和C,C就更多了,对应ADBF……

上面的示例图,每个带数据的英文字符和圈圈,叫图的顶点(Vertex),顶点间由线连接来确定连通关系。当然连通线可以无向,也可以有向,甚至带权。本例则是无向的连接线,也就是双方都可以互通

进入正题,比如我们从顶点A出发,怎么遍历整幅图的所有顶点呢?有两种方案:一种是尽可能深地走,就像找路一样,不走到死胡同则一直走,走到死胡同了则退回来再探寻第二个方向;另一种是先找遍下一个路口,然后再找遍下下个路口,直到所有都是死胡同。其中第一个叫做"深度优先搜索",英文缩写为DFS,第二个叫"广度优先搜索",英文缩写为BFS;

下面我们创建图顶点类,以及生成上面图例的方法,此方法返回搜索起点的顶点,也就是A顶点:

import java.util.HashSet;
import java.util.Set;

/**
 * 图的顶点类
 * @Author: LiYang
 * @Date: 2019/9/1 1:11
 */
public class Vertex {

    //顶点的值
    public String value;

    //是否被访问过的标记
    public boolean visited;

    //相邻顶点
    public Set<Vertex> neighbors = new HashSet<>();

    /**
     * 构造方法,传入顶点的值
     * @param value
     */
    public Vertex(String value) {
        this.value = value;
    }

    /**
     * 顶点添加相邻节点,可链式添加
     * @param neighbor
     * @return
     */
    public Vertex addNeighbors(Vertex neighbor){
        neighbors.add(neighbor);
        return this;
    }

    /**
     * 创建示例图
     * @return
     */
    public static Vertex getExampleGraph(){
        //图的顶点
        Vertex vertexA = new Vertex("A");
        Vertex vertexB = new Vertex("B");
        Vertex vertexC = new Vertex("C");
        Vertex vertexD = new Vertex("D");
        Vertex vertexE = new Vertex("E");
        Vertex vertexF = new Vertex("F");
        Vertex vertexG = new Vertex("G");
        Vertex vertexH = new Vertex("H");
        Vertex vertexI = new Vertex("I");
        Vertex vertexJ = new Vertex("J");
        Vertex vertexK = new Vertex("K");

        //按照示例图,添加相邻顶点
        vertexA.addNeighbors(vertexC).addNeighbors(vertexD);
        vertexB.addNeighbors(vertexE).addNeighbors(vertexC);
        vertexC.addNeighbors(vertexB).addNeighbors(vertexF).addNeighbors(vertexD).addNeighbors(vertexA);
        vertexD.addNeighbors(vertexA).addNeighbors(vertexC);
        vertexE.addNeighbors(vertexH).addNeighbors(vertexI).addNeighbors(vertexF).addNeighbors(vertexB);
        vertexF.addNeighbors(vertexG).addNeighbors(vertexC).addNeighbors(vertexE);
        vertexG.addNeighbors(vertexF);
        vertexH.addNeighbors(vertexE).addNeighbors(vertexJ);
        vertexI.addNeighbors(vertexE).addNeighbors(vertexK);
        vertexJ.addNeighbors(vertexK).addNeighbors(vertexH);
        vertexK.addNeighbors(vertexI).addNeighbors(vertexJ);

        //返回搜索的起始顶点
        return vertexA;
    }

}

接下来我们通过Java的代码,实现 “深度优先搜索(DFS)” 和 " 广度优先搜索(BFS) ",有兴趣的朋友可以照着示例代码,用Debug模式一步步探寻这两种图的搜索方式的机理:

import java.util.LinkedList;
import java.util.Queue;

/**
 * 图的类
 * @Author: LiYang
 * @Date: 2019/9/1 1:20
 */
public class Graph {

    /**
     * 深度优先搜索 DFS
     * @param vertex 起始顶点
     */
    public static void DFS(Vertex vertex){
        //如果该顶点已被访问,则结束递归
        if (vertex.visited){
            return;
        }

        //打印顶点的值(访问)
        System.out.print(vertex.value + "  ");
        //设置顶点的访问状态为已访问
        vertex.visited = true;

        //递归搜索相邻节点
        for (Vertex neighbor : vertex.neighbors){
            DFS(neighbor);
        }
    }

    /**
     * 广度优先搜索 BFS
     * @param vertex 起始顶点
     */
    public static void BFS(Vertex vertex){
        //新建一个队列,用LinkedList实现
        Queue<Vertex> graphQueue = new LinkedList<>();
        //加入搜索起始顶点
        graphQueue.add(vertex);

        //队列未空,则还有可搜索的顶点
        while (graphQueue.size() > 0){
            //队列出队一个顶点
            Vertex currentVertex = graphQueue.poll();

            //如果顶点没有被访问
            if (!currentVertex.visited){
                //打印顶点的值(访问)
                System.out.print(currentVertex.value + "  ");
                //设置顶点的访问状态为已访问
                currentVertex.visited = true;

                //出队的那个顶点访问后,将其相邻顶点入队
                for (Vertex neighbor : currentVertex.neighbors){
                    graphQueue.add(neighbor);
                }
            }
        }
    }

    /**
     * 测试深度优先搜索和广度优先搜索
     * @param args
     */
    public static void main(String[] args) {
        //深度优先搜索
        System.out.print("DFS:");
        DFS(Vertex.getExampleGraph());

        //换行
        System.out.println();

        //广度优先搜索
        System.out.print("BFS:");
        BFS(Vertex.getExampleGraph());
    }

}

最后,执行main方法,控制台打印两种搜索方法遍历图顶点的顺序:

DFS:A  D  C  B  E  H  J  K  I  F  G  
BFS:A  D  C  B  F  E  G  H  I  J  K  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值