java迷宫广度优先搜索_BFS 广度优先搜索

图,一种可以表示对象复杂连接关系的数据结构。其较可以其他数据结构而言,可以很方便描述地图、电路、网络等拓扑结构。本文将介绍图的描述方法和基本的图搜索算法——BFS 广度优先搜索

定义

图(Graph),是由一组顶点(Vertex)和一组能够将两个顶点相连的边(Edge)所组成。具体地,根据边是否有方向,可划分为有向图、无向图;根据边是否有权重值,可划分为加权图、无加权图。如下图所示,其是一个顶点数V=5、边数E=6的无向无加权图G1(V,E)

[Note]:平行边:连接同一对顶点的两条边

自环:一条顶点与自身连接的边

描述

现已无向无加权图G1(V,E)为例,介绍图的表示方法

1. 邻接矩阵

邻接矩阵Adjacency Matrix,是一个 VxV 矩阵,当元素 a(v,w) 值为1时,即表示顶点v到顶点w之间有一点边。易知,无向图的邻接矩阵是一个对称矩阵;对于加权图而言,邻接矩阵中表示某条边存在的元素 a(v,w) 可设为加权值。无向无加权图G1使用邻接矩阵描述如下:

equation?tex=Adjacency+%5C++Matrix+%3D++%5Cbegin%7Bbmatrix%7D+0+%26+1+%26+1+%26+0+%26+1+%5C%5C+1+%26+0+%26+0+%26+0+%26+0+%5C%5C+1+%26+0+%26+0+%26+1+%26+1+%5C%5C+0+%26+0+%26+1+%26+0+%26+1+%5C%5C+1+%26+0+%26+1+%26+1+%26+0+%5C%5C+%5Cend%7Bbmatrix%7D+%5C%5C

缺点:当一个图很大(顶点数很多)而边数较少,此时若用邻接矩阵表示时,其矩阵是一个稀疏矩阵,且矩阵大小为VxV,这将大大浪费存储空间

表示无向图时,由于是对称矩阵,存在冗余,浪费存储空间

无法表示平行边

2.关联矩阵

关联矩阵 Incidence Matrix,是一个 VxE 矩阵,行表示顶点,列表示边。对于一个无向图而言,当某列中有2个元素的值均为1,即表示该边所连接的两个顶点。即,元素 a(v,w)、a(v,k) 值均为1时表示第v条边的两个顶点分别是w和k;对于一个有向图而言,元素 a(v,w)、a(v,k) 值分别为1、-1时,表示第v条边的起点、终点分别是w、k;当某列中,有一个元素的值为2,即可表示该顶点有一个自环;对于一个加权图而言,可以在关联矩阵下方再增加一行,用于表示各边的加权值。无向无加权图G1使用关联矩阵描述如下:

equation?tex=Incidence+%5C++Matrix+%3D++%5Cbegin%7Bbmatrix%7D+1+%26+1+%26+1+%26+0+%26+0+%26+0+%5C%5C+1+%26+0+%26+0+%26+0+%26+0+%26+0+%5C%5C+0+%26+1+%26+0+%26+1+%26+1+%26+0+%5C%5C+0+%26+0+%26+0+%26+1+%26+0+%26+1+%5C%5C+0+%26+0+%26+1+%26+0+%26+1+%26+1+%5C+%5Cend%7Bbmatrix%7D++%5C%5C

缺点:获取某个顶点的全部邻接点时,需要遍历图的所有边

3.邻接表

邻接表Adjacency List 是一个以顶点为索引的哈希表,然后该哈希表与每个顶点的邻接点列表相关联。无向无加权图G1使用邻接表描述如下:

BFS 算法

基本原理

对于图而言,广度优先搜索(BFS) 和 深度优先搜索(DFS) 是两种最基础的图搜索算法,这里介绍前者——BFS。该算法主要用于解决在一个无加权图下找到从起点S至指定点W的最短路径。该算法搜索路径首先从起点S开始,查找距离起点S一条边的顶点集合中是否存在顶点W;若没有则在所有距离起点S两条边的顶点集合中继续查找,直到找到顶点W。BFS算法的搜索图解过程,如下图所示,其过程类似于走迷宫,当走到分岔处,其会自动分裂成多个人,同时向多个分岔去前进搜索;而当多个分岔合并到一处时,亦会变为一个人继续前进搜索

算法流程

为保证先搜索相同距离长度的路径,该算法使用队列的FIFO特性来保存已经遇到但还未被搜索的分岔路径

1. 将起点加入队列,并将该顶点状态标记为已搜索;重复Step 2 - 4,直到队列为空

2. 从队列中取出一个顶点V

3. 获取顶点V所有的未被搜索过的邻接点列表 toSearchList

4. 对邻接点列表 toSearchList 中所有顶点执行:加入队列、状态标记为已搜索、记录访问该顶点路径的前驱顶点

Java Demo

现已上文图解的无向图为例,通过Java实现BFS算法

/*** BFS*/

public class BFS {

public static void BFSDemo() {

Undigraph undigraph = getUndigraph(); // 通过邻接表构造一个无向图 Integer vertexNum = undigraph.getVertexNum(); // 该无向图的顶点数 Integer start = 0; // 指定遍历起点 // BFS结果: 从起点到该点的最短路径上的上一个位置点 // 即 previousVertex[v] = w, 意为 start → ... → w → v int[] previousVertex = new int[vertexNum];

Boolean status = BFS(undigraph, start, previousVertex);

if( status ) {

visualPath(start, previousVertex);

}

}

/*** 广度优先遍历* @param undigraph 图* @param start 起点* @return*/

private static Boolean BFS( Undigraph undigraph, Integer start, int[] previousVertex) {

Integer vertexNum = undigraph.getVertexNum(); // 该无向图的顶点数

Deque deque = new LinkedList<>(); // 遍历队列 int[] markArray = new int[vertexNum]; // 访问状态标记数组 0: 未访问, 1: 已访问

// 将起点加入队列中 deque.offer( start );

markArray[start] = 1; // 标记状态为 已访问

while( !deque.isEmpty() ) {

Integer currentVertex = deque.poll(); // 从队列取出一个顶点

// 该点无邻接点 if( !undigraph.getAdjacencyList().containsKey(currentVertex) ) {

return false;

}

// 取出该点的邻接点 List adjacencyList = undigraph.getAdjacencyList().get(currentVertex);

for( Integer nextVertex : adjacencyList) {

if( markArray[nextVertex] != 1 ) { // 当前点的邻接点未访问,则进行访问 markArray[nextVertex] = 1; // 标记状态为: 已访问 deque.offer( nextVertex ); // 将邻接点加入队列 previousVertex[nextVertex] = currentVertex; // 记录访问路径 }

}

}

return true;

}

/*** BFS 结果可视化* @param start 起点* @param resultPath BFS结果路径*/

private static void visualPath(Integer start, int[] resultPath) {

for( int i=0; i

List path = new LinkedList();

Integer vertex = i;

while (vertex != start) {

path.add( vertex.toString() );

vertex = resultPath[vertex];

}

path.add(vertex.toString());

Collections.reverse(path);

String pathStr = path.stream().collect( Collectors.joining("->") );

System.out.println(pathStr);

}

}

/*** 根据邻接表构造无向图* @return*/

private static Undigraph getUndigraph() {

Map> adjacencyList = new HashMap<>();

adjacencyList.put(0, Arrays.asList(1, 2, 5) );

adjacencyList.put(1, Arrays.asList(0, 2) );

adjacencyList.put(2, Arrays.asList(0, 1, 3, 4) );

adjacencyList.put(3, Arrays.asList(2, 4, 5) );

adjacencyList.put(4, Arrays.asList(2, 3) );

adjacencyList.put(5, Arrays.asList(0, 3) );

Undigraph undigraph = new Undigraph();

undigraph.setAdjacencyList( adjacencyList );

undigraph.setVertexNum( adjacencyList.size() );

return undigraph;

}

}

/*** 无向图*/

@Data

class Undigraph {

/*** 邻接表*/

private Map> adjacencyList;

/*** 顶点数*/

private Integer vertexNum;

}

算法结果:

应用无加权图的最短路径问题

二分图判定问题

参考文献算法(第4版) Robert Sedgewick、Kevin Wayne 著

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值