资讯专栏INFORMATION COLUMN

广度优先,深度优先,寻求最短路径。

bawn / 3309人阅读

一、应用

深度优先:是否存在通路,寻找所有解。

广度优先遍历:寻求最优解,寻求最短路径

1.邻接矩阵JAVA代码实现

邻接矩阵可以使用一个二维数组来表示

public class GraphTest {

  // 节点
  public static class Vertex {
    public String name;
    private boolean isVisited;

    public Vertex(String name) {
      this.name = name;
      this.isVisited = false;
    }

    public void displayName() {
      System.out.println("name:" + name);
    }
  }

  // 图
  public static class Graph {
    // 存节点数据
    private Vertex[] vertices;
    // 矩阵
    private int[][] matrix;
    // 队列,用于BFS
    private Queue queue = new LinkedList<>();
    // 栈,用于DFS
    private Stack stack = new Stack<>();

    private Map dependencyMap = new HashMap<>();

    public Graph(Vertex[] vertices, int[][] matrix) {
      this.vertices = vertices;
      this.matrix = matrix;
    }

    // 找到未访问过的邻接点
    public List getUnvisitedVertex(int i) {
      List unvisitedVertices = new ArrayList<>();
      for (int j = 0; j < matrix.length; j++) {
        if (matrix[i][j] > 0 && !vertices[j].isVisited) {
          unvisitedVertices.add(j);
        }
      }
      return unvisitedVertices;
    }

    // 广度优先
    public void bfs(int vertex) {
      queue.offer(vertex);

      while (!queue.isEmpty()) {
        int v = queue.poll();
        if (!vertices[v].isVisited) {
          vertices[v].displayName();
          vertices[v].isVisited = true;

          List unvisitedVertices = getUnvisitedVertex(v);
          unvisitedVertices.forEach(uv -> {
            queue.offer(uv);
            dependencyMap.putIfAbsent(uv, v);
          });
        }
      }
    }

    // 深度优先
    public void dfs(int vertex) {
      stack.push(vertex);

      while (!stack.isEmpty()) {
        int v = stack.pop();
        if (!vertices[v].isVisited) {
          vertices[v].displayName();
          vertices[v].isVisited = true;

          List unvisitedVertices = getUnvisitedVertex(v);
          unvisitedVertices.forEach(uv -> stack.push(uv));
        }
      }
    }

    // 深度优先递归实现
    public void dfsRecursion(int vertex) {
      if (!vertices[vertex].isVisited) {
        vertices[vertex].displayName();
        vertices[vertex].isVisited = true;

        List unvisitedVertices = getUnvisitedVertex(vertex);
        unvisitedVertices.forEach(this::dfsRecursion);
      }
    }

    public void printShortestPath(int start, int end) {
      bfs(start);

      String symbol = "-->";
      StringBuilder sb = new StringBuilder();
      sb.append(vertices[end].name);
      sb.append(symbol);
      while (dependencyMap.get(end) != null) {
        sb.append(vertices[dependencyMap.get(end)].name);
        sb.append(symbol);
        end = dependencyMap.get(end);
      }
      String path = sb.substring(0, sb.lastIndexOf(symbol));
      System.out.println(path);
    }

    public void clear() {
      stack.clear();
      queue.clear();
      dependencyMap.clear();
      for (int i = 0; i < vertices.length; i++) {
        vertices[i].isVisited = false;
      }
    }

  }

  public static void main(String[] args) {
    Vertex[] vertices = {
            new Vertex("v0"),
            new Vertex("v1"),
            new Vertex("v2"),
            new Vertex("v3"),
            new Vertex("v4")
    };

    int[][] matrix = new int[][]{
            {0, 0, 1, 1, 0},
            {0, 0, 1, 0, 1},
            {1, 1, 0, 0, 1},
            {1, 0, 0, 0, 1},
            {0, 1, 1, 1, 0}
    };

    Graph graph = new Graph(vertices, matrix);

    System.out.println("广度优先搜索:");
    graph.bfs(0);
    graph.clear();

    System.out.println("深度优先搜索:");

    graph.dfs(0);
    graph.clear();

    System.out.println("递归深度优先搜索:");

    graph.dfsRecursion(0);
    graph.clear();

    System.out.println("打印最短路径:");

    graph.printShortestPath(0, 4);
  }
}

打印结果
广度优先搜索:
name:v0
name:v2
name:v3
name:v1
name:v4
深度优先搜索:
name:v0
name:v3
name:v4
name:v2
name:v1
递归深度优先搜索:
name:v0
name:v2
name:v1
name:v4
name:v3
打印最短路径:
name:v0
name:v2
name:v3
name:v1
name:v4
v4-->v2-->v0

2.邻接表JAVA代码实现

邻接表可以使用数组+链表,链表+链表,哈希表等等数据结构来表示。在java中,map结构非常适合表示邻接表

public class GraphTest {
  public static void main(String[] args){
    //初始化先建立起各个节点信息,以及对应的直接子节点列表
    HashMap map = new HashMap<>();
    map.put("V0", new String[] {"V2","V3"});
    map.put("V1", new String[] {"V2","V4"});
    map.put("V2", new String[] {"V0","V1","V4"});
    map.put("V3", new String[] {"V0","V4"});
    map.put("V4", new String[] {"V1","V2","V3"});
    //获取从A到H的最短路径节点链表
    Node target = findTarget("V0","V4",map);
    //打印出最短路径的各个节点信息
    printSearPath(target);

  }

  /**
   * 打印出到达节点target所经过的各个节点信息
   * @param target
   */
  static void printSearPath(Node target) {
    if (target != null) {
      System.out.print("找到了目标节点:" + target.id + "
");

      List searchPath = new ArrayList();
      searchPath.add(target);
      Node node = target.parent;
      while(node!=null) {
        searchPath.add(node);
        node = node.parent;
      }
      String path = "";
      for(int i=searchPath.size()-1;i>=0;i--) {
        path += searchPath.get(i).id;
        if(i!=0) {
          path += "-->";
        }
      }
      System.out.print("步数最短:"+path);
    } else {
      System.out.print("未找到了目标节点");
    }
  }

  /**
   * 从指定的开始节点 startId ,查询到目标节点targetId 的最短路径
   * @param startId
   * @param targetId
   * @param map
   * @return
   */
  static Node findTarget(String startId,String targetId,HashMap map) {
    List hasSearchList = new ArrayList();
    LinkedList queue = new LinkedList();
    queue.offer(new Node(startId,null));
    while(!queue.isEmpty()) {
      Node node = queue.poll();

      if(hasSearchList.contains(node.id)) {
        //跳过已经搜索过的,避免重复或者死循环
        continue;
      }
      System.out.print("判断节点:" + node.id +"
");
      if (targetId.equals(node.id)) {
        return node;
      }
      hasSearchList.add(node.id);
      if (map.get(node.id) != null && map.get(node.id).length > 0) {
        for (String childId : map.get(node.id)) {
          queue.offer(new Node(childId,node));
        }
      }
    }

    return null;
  }

  /**
   * 节点对象
   * @author Administrator
   *
   */
  static class Node{
    //节点唯一id
    public String id;
    //该节点的直接父节点
    public Node parent;
    //该节点的直接子节点
    public List childs = new ArrayList();
    public Node(String id,Node parent) {
      this.id = id;
      this.parent = parent;
    }
  }
}

打印:
判断节点:V0
判断节点:V2
判断节点:V3
判断节点:V1
判断节点:V4
找到了目标节点:V4
步数最短:V0-->V2-->V4

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/75297.html

相关文章

  • 算法-图和图算法

    摘要:图的定义用图对现实中的系统建模可以用图对现实中的很多系统建模比如对交通流量建模顶点可以表示街道的十字路口边可以表示街道加权的边可以表示限速或者车道的数量建模人员可以用这个系统来判断最佳路线及最有可能堵车的街道任何运输系统都可以用图来建模比如 图的定义 用图对现实中的系统建模 可以用图对现实中的很多系统建模. 比如对交通流量建模, 顶点可以表示街道的十字路口, 边可以表示街道. 加权的边...

    Anshiii 评论0 收藏0
  • 图的JS实现

    摘要:图的实现如下采用邻接表结构实现。由于本次示例的是无向图,因此每个顶点都互相增加为邻接点。然而由于本次示例的图为无向图,会出现重复遍历的情况,例如顶点的邻接点有,的邻接点有。 图的定义 图就是由若干个顶点和边连接起来的一种结构。很多东西都可以用图来说明,例如人际关系,或者地图。 其中图还分为有向图和无向图。如下就是有向图 图的数据结构 对于图这种关系,可以通过两种方式来存储。 领接表 将...

    LeanCloud 评论0 收藏0
  • 基于JavaScript求解八数码短路并生成动画效果

    摘要:写在最前本次分享一下通过广度优先搜索解决八数码问题并展示其最短路径的动画效果。一个排列中逆序的总数就称为这个排列的逆序数。如果起始状态与结束状态的逆序数的奇偶性相同,则说明状态可达,反之亦然。 写在最前 本次分享一下通过广度优先搜索解决八数码问题并展示其最短路径的动画效果。 欢迎关注我的博客,不定期更新中—— 效果预览 该效果为从[[2, 6, 3],[4, 8, 0],[7, 1, ...

    Jioby 评论0 收藏0
  • 队列和 BFS —— 栈和 DFS

    摘要:队列和广度优先搜索的一个常见应用是找出从根结点到目标结点的最短路径。然后在每一轮中,我们逐个处理已经在队列中的结点,并将所有邻居添加到队列中。这就是我们在中使用队列的原因。 队列和 BFS: 广度优先搜索(BFS)的一个常见应用是找出从根结点到目标结点的最短路径。 示例 这里我们提供一个示例来说明如何使用 BFS 来找出根结点 A 和目标结点 G 之间的最短路径。 showImg(h...

    Kyxy 评论0 收藏0
  • 算法系列——JavaScript中广度优先搜索思想实现

    摘要:散列表上面的地图向我们展示了如何用广度优先搜索的思想找到北京到广州的最短路线。在广度优先搜索中,我们需要用到队列的这种思想来实现查找。建立了下面这个模型武汉广州西藏上海上海武汉广州代码完整实现,利用递归和广度优先搜索的思想实现。 什么是广度优先搜索? 如果只是是背概念,幼儿园的小朋友都能背下来念给你听。 假设看这篇文章的都和我一样是个前端工程师,我们要从广度优先搜索(BFS)中学到什么...

    everfly 评论0 收藏0

发表评论

0条评论

bawn

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<