Java实现利用广度优先遍历(BFS)计算最短路径的方法_java

本文实例讲述了Java实现利用广度优先遍历(BFS)计算最短路径的方法。分享给大家供大家参考。具体分析如下:

我们用字符串代表图的顶点(vertax),来模拟学校中Classroom, Square, Toilet, Canteen, South Gate, North Gate几个地点,然后计算任意两点之间的最短路径。

如下图所示:

如,我想从North Gate去Canteen, 程序的输出结果应为:

BFS: From [North Gate] to [Canteen]:
North Gate
Square
Canteen

首先定义一个算法接口Algorithm:

public interface Algorithm {
  /**
   * 执行算法
   */
  void perform(Graph g, String sourceVertex);
  /**
   * 得到路径
   */
  Map<String, String> getPath();
}

然后,定义图:

/**
 * (无向)图
 */
public class Graph {
  // 图的起点
  private String firstVertax;
  // 邻接表
  private Map<String, List<String>> adj = new HashMap<>();
  // 遍历算法
  private Algorithm algorithm;
  public Graph(Algorithm algorithm) {
    this.algorithm = algorithm;
  }
  /**
   * 执行算法
   */
  public void done() {
    algorithm.perform(this, firstVertax);
  }
  /**
   * 得到从起点到{@code vertex}点的最短路径
   * @param vertex
   * @return
   */
  public Stack<String> findPathTo(String vertex) {
    Stack<String> stack = new Stack<>();
    stack.add(vertex);
    Map<String, String> path = algorithm.getPath();
    for (String location = path.get(vertex) ; false == location.equals(firstVertax) ; location = path.get(location)) {
      stack.push(location);
    }
    stack.push(firstVertax);
    return stack;
  }
  /**
   * 添加一条边
   */
  public void addEdge(String fromVertex, String toVertex) {
    if (firstVertax == null) {
      firstVertax = fromVertex;
    }
    adj.get(fromVertex).add(toVertex);
    adj.get(toVertex).add(fromVertex);
  }
  /**
   * 添加一个顶点
   */
  public void addVertex(String vertex) {
    adj.put(vertex, new ArrayList<>());
  }
  public Map<String, List<String>> getAdj() {
    return adj;
  }
}

这里我们使用策略设计模式,将算法与Graph类分离,通过在构造Graph对象时传入一个Algorithm接口的实现来为Graph选择遍历算法。

public Graph(Algorithm algorithm) {
    this.algorithm = algorithm;
  }

无向图的存储结构为邻接表,这里用一个Map表示邻接表,map的key是学校地点(String),value是一个与该地点相连通的地点表(List<String>)。

// 邻接表
  private Map<String, List<String>> adj = new HashMap<>();

然后,编写Algorithm接口的BFS实现:

/**
 * 封装BFS算法
 */
public class BroadFristSearchAlgorithm implements Algorithm {
  // 保存已经访问过的地点
  private List<String> visitedVertex;
  // 保存最短路径
  private Map<String, String> path;
  @Override
  public void perform(Graph g, String sourceVertex) {
    if (null == visitedVertex) {
      visitedVertex = new ArrayList<>();
    }
    if (null == path) {
      path = new HashMap<>();
    }
    BFS(g, sourceVertex);
  }
  @Override
  public Map<String, String> getPath() {
    return path;
  }
  private void BFS(Graph g, String sourceVertex) {
    Queue<String> queue = new LinkedList<>();
    // 标记起点
    visitedVertex.add(sourceVertex);
    // 起点入列
    queue.add(sourceVertex);
    while (false == queue.isEmpty()) {
      String ver = queue.poll();
      List<String> toBeVisitedVertex = g.getAdj().get(ver);
      for (String v : toBeVisitedVertex) {
        if (false == visitedVertex.contains(v)) {
          visitedVertex.add(v);
          path.put(v, ver);
          queue.add(v);
        }
      }
    }
  }
}

其中,path是Map类型,意为从 value 到 key 的一条路径。

BFS算法描述:

1. 将起点标记为已访问并放入队列。
2. 从队列中取出一个顶点,得到与该顶点相通的所有顶点。
3. 遍历这些顶点,先判断顶点是否已被访问过,如果否,标记该点为已访问,记录当前路径,并将当前顶点入列。
4. 重复2、3,直到队列为空。

测试用例:

String[] vertex = {"North Gate", "South Gate", "Classroom", "Square", "Toilet", "Canteen"};
  Edge[] edges = {
      new Edge("North Gate", "Classroom"),
      new Edge("North Gate", "Square"),
      new Edge("Classroom", "Toilet"),
      new Edge("Square", "Toilet"),
      new Edge("Square", "Canteen"),
      new Edge("Toilet", "South Gate"),
      new Edge("Toilet", "South Gate"),
  };
@Test
  public void testBFS() {
    Graph g = new Graph(new BroadFristSearchAlgorithm());
    addVertex(g);
    addEdge(g);
    g.done();
    Stack<String> result = g.findPathTo("Canteen");
    System.out.println("BFS: From [North Gate] to [Canteen]:");
    while (!result.isEmpty()) {
      System.out.println(result.pop());
    }
  }

希望本文所述对大家的java程序设计有所帮助。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
, 广度优先遍历
最短路径
bfs广度优先搜索算法、广度优先搜索最短路径、广度优先最短路径、广度优先遍历、图的广度优先遍历,以便于您获取更多的相关知识。

时间: 2024-11-01 09:09:02

Java实现利用广度优先遍历(BFS)计算最短路径的方法_java的相关文章

java中利用反射调用另一类的private方法的简单实例_java

我们知道,Java应用程序不能访问持久化类的private方法,但Hibernate没有这个限制,它能够访问各种级别的方法,如private, default, protected, public. Hibernate是如何实现该功能的呢?答案是利用JAVA的反射机制,如下:  import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class ReflectDemo

利用SilverLight 遍历父子控件通用方法

利用silverlight 遍历父子控件通用方法 silverlight中datagrid找元素,真是麻烦,没有rows对象,无法遍历.从网上找来这些方法,挺好用的: public class vthelper() {         public t getparentobject<t>(dependencyobject obj, string name) where t : frameworkelement         {             dependencyobject pa

Java利用序列化实现对象深度clone的方法_java

本文实例讲述了Java利用序列化实现对象深度clone的方法.分享给大家供大家参考.具体实现方法如下: ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(byteOut); out.writeObject(obj); ByteArrayInputStream byteIn = new ByteArrayInputStream(by

利用java反射机制实现自动调用类的简单方法_java

1. 新建TestServlet类 package com.yanek.test; import java.io.IOException; import java.lang.reflect.Method; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.ht

Java中计算时间差的方法_java

本文实例讲述了Java中计算时间差的方法.分享给大家供大家参考.具体如下: 假设现在是2004-03-26 13:31:40 过去是:2004-01-02 11:30:24 要获得两个日期差,差的形式为:XX天XX小时XX分XX秒 方法一: DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { Date d1 = df.parse("2004-03-26 13:31:40"); Date

java 结合jQuery实现跨域名获取数据的方法_java

一.什么是跨域? 由于浏览器出于安全的考虑,采取了同源策略的限制,使得jQuery无法直接跨域名互相操作对象或数据.例如:a.com 域名下的 a.html页面利用jQuery无法操作b.com 域名下b.html页面的对象或是数据, 并且默认情况下也不能操作test.a.com域名下的 test.html的 对象或是数据 .只要满足下面条件的jQuery都会视为跨域名: 1.主域相同,子域不同,如xxx.aaa.com和yyy.aaa.com 2.域名相同,端口不同,如xxx.aaa.com:

java实现从网上下载图片到本地的方法_java

本文实例讲述了java实现从网上下载图片到本地的方法.分享给大家供大家参考.具体如下: import java.io.*; import java.net.MalformedURLException; import java.net.URL; public static void writeFile(String strUrl,String fileName){ URL url = null; try { url = new URL(strUrl); } catch (MalformedURLE

java在网页上面抓取邮件地址的方法_java

本文实例讲述了java在网页上面抓取邮件地址的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: import java.io.BufferedReader;  import java.io.InputStreamReader;  import java.net.URL;  import java.util.regex.Matcher;  import java.util.regex.Pattern;    public class h1  {     public stati

java持久层框架mybatis防止sql注入的方法_java

sql注入大家都不陌生,是一种常见的攻击方式,攻击者在界面的表单信息或url上输入一些奇怪的sql片段,例如"or '1'='1'"这样的语句,有可能入侵参数校验不足的应用程序.所以在我们的应用中需要做一些工作,来防备这样的攻击方式.在一些安全性很高的应用中,比如银行软件,经常使用将sql语句全部替换为存储过程这样的方式,来防止sql注入,这当然是一种很安全的方式,但我们平时开发中,可能不需要这种死板的方式. mybatis框架作为一款半自动化的持久层框架,其sql语句都要我们自己来手