搜索算法
搜索算法是利用计算机的高性能来有目的的穷举一个问题解空间的部分或所有的可能情况,从而求出问题的解的一种方法。在我们参加各种竞赛,以及参加各种面试我们难免会碰到需要使用搜索算法的问题,甚至在我们项目开发的过程中,也会使用到搜索算法。在此,为大家介绍两种常用的搜索算法,广度优先搜索(BFS)和深度优先搜索(DFS)
广度优先搜索
广度优先搜索算法(Breadth-First-Search),就是我们常说的BFS,是对树这种数据结构的遍历,它其实就是一种“地毯式”层层推进的搜索策略,即先查找离起始顶点最近的,然后是次近的,依次往外搜索。因此,在我们寻找最短路径的时候,我们经常会用到BFS这种搜索算法,例如我们常见的迷宫问题。举个例子
如图,假设#表示不能通行,.(小数点)表示可以通行,我们需要找到从左上角(坐标(0,0))到右下角(坐标(4,4))的最短路径并将路径输出,首先我们能想到的解决办法就是BFS搜索算法。那么,BFS算法究竟是怎样找到最短路径并输出的呢?我们先来解决以下两个问题
如何避免走回头路?(多次走到了同一个位置)如何将最短的路径进行输出?
- 对于避免走回头路,我采取的方法是定义一个boolean类型的二维数组visited,大小与迷宫大小相同,初始值让其均为false,每当走过到一个点,就让该点变成true,以后为true的点就不让其访问。
- 对于路径的输出,采取的方法是定义一个与迷宫大小相同的二维数组path,每个点存放该点从何处来,例如该图(0,1)是从(0,0)走过来的,我就让path[0] [1] = (0,0),往后依次类推
接下来给大家分析一下BFS算法解决迷宫问题的过程
- 迷宫起点坐标为(0,0),visited[0][0] = true很明显,向左走,向上走不在迷宫的范围,所以只能向下或向右,但下方为#,所以只能走到(0,1),visited[0] [1] = true path[0] [1] = (0,0)
- (0,1)点同上只能向下走到(1,1),visited[1] [1] = true path[1] [1] = (0,1)
- (1,1)点可以向四个方向走,但左边和下边路不通,上方(0,1)对应的visited[0] [1] = true,我们也不需要考虑,所以向右到(1,2),visited[1] [2] = true path[1] [2] = (1,1)
- (1,2)可以向右或向下走所以visited[1] [3] = true path[1] [3] = (1,2) visited[2][2]=true paht[2] [2] = (1,2)
- (1,3)可以往上走,visited[0][3] = true,paht[0][3] = (1,3),(2,2)可以往下走visited[3][2] = true,paht[3][2] = (2,2)
- (0,3)无路可走,此条分支不必考虑,(3,2)可以向右,下,左三个方向走,所以visited[3][3]=true paht[3][3]=(3,2) visited[4][2]=true path[4][2]=(3,2) visited[3][2]=true path[3][1]=(3,2)
- (3,3)只能向下走,vistied[4][3] = true path[4][3]=(3,3),原本(4,2)可以向右到(4,3),但visited[4][3]此时已为true,(3,1)无路可走
- (4,3)向右到达终点(4,4),visited[4] [4] = true,path[4][4]=(4,3)
因此从path[4][4]往回输出可得到路径
(0,0)->(0,1)->(1,1)->(1,2)->(2,2)->(3,2)->(3,3)->(4,3)->(4,4)
为了进一步方便大家理解,大家可以看下图,同一层从左到右依次执行,执行完当前层执行下一层
代码在此基础上进行了升级,地图长度可以自己指定,地图自己绘制,起点坐标和终点坐标也可以自己指定,代码如下,有一定的理解难度,如果看不懂请不要灰心,时间会给你答案。
package com.harbor.method;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
/**
* 使用bfs解决迷宫问题
* 用户输入迷宫的长(len)和宽(width)
* 并输入迷宫(char[] maze)
* '.'代表可通行,'#'代表不可通行
* 用户输入迷宫起点坐标和终点坐标
* 此程序输出最短线路
* @author harborGao
* @create 2020/3/20
*/
public class MazeOfBfs {
public static int startX;
public static int startY;
public static int endX;
public static int endY;
public static char[][] maze;
public static int len;
public static int width;
//每访问一个点让该点入队,直至该点所有子节点访问完成出队
public static Queue<Point> queue;
//记录走过的路,例如终点为(3,3),它是从(2,3)走过来的,则path[3][3]中x存放2,y存放3
public static Point[][] path;
public static boolean[][] visited;
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
//迷宫的长
len = input.nextInt();
//迷宫的宽
width = input.nextInt();
//根据迷宫长宽定义迷宫大小
maze = new char[len][width];
//因迷宫中每个点都有可能被访问,所以大小与迷宫大小相同
path = new Point