广度优先搜索学习5例之一
广度优先搜索学习五例之一
有两种常用的方法可用来搜索图:即深度优先搜索和广度优先搜索。它们最终都会到达所有连通的顶点。深度优先搜索通过栈或递归来实现,而广度优先搜索通过队列来实现。
广度优先搜索:
它首先访问起始顶点的所有邻接点,然后再访问较远的区域。它是用队列来实现的。
下面图中的数字显示了广度优先搜索顶点被访问的顺序。

图的广度优先搜索,要遵守以下规则:
(0) 选取某一顶点作为开始搜索的起点(当前顶点)入队列,标记为已访问。
(1) 访问当前顶点的下一个未被访问的邻接点,这个点必须是当前顶点的邻接点,标记它,并把它插入到队列中。
(2) 如果因为已经没有未访问的邻接点而不能执行规则1时,那么从队列头取一个顶点,并使其成为当前顶点。
(3) 如果因为队列为空而不能执行规则2,则搜索结束。
例二:迷宫问题
定义一个二维数组:
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
Input
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。
Output
左上角到右下角的最短路径,格式如样例所示。
Sample Input
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
Sample Output
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)
下载源码
有两种常用的方法可用来搜索图:即深度优先搜索和广度优先搜索。它们最终都会到达所有连通的顶点。深度优先搜索通过栈或递归来实现,而广度优先搜索通过队列来实现。
广度优先搜索:
它首先访问起始顶点的所有邻接点,然后再访问较远的区域。它是用队列来实现的。
下面图中的数字显示了广度优先搜索顶点被访问的顺序。
图的广度优先搜索,要遵守以下规则:
(0) 选取某一顶点作为开始搜索的起点(当前顶点)入队列,标记为已访问。
(1) 访问当前顶点的下一个未被访问的邻接点,这个点必须是当前顶点的邻接点,标记它,并把它插入到队列中。
(2) 如果因为已经没有未访问的邻接点而不能执行规则1时,那么从队列头取一个顶点,并使其成为当前顶点。
(3) 如果因为队列为空而不能执行规则2,则搜索结束。
例一:文件目录的广度优先遍历 private static void BFS(File file) throws IOException{ System.out.println(file.getCanonicalPath());//先访问起点 Queue< File> queue = new LinkedList< File>(); queue.offer(file); //起点入队 File fileInQueue = null; while (queue.size() > 0) { fileInQueue = queue.poll(); //当前顶点出队列 File[] files =fileInQueue.listFiles(); //求出当前顶点的所有邻接点 for (File eachFile : files) {//依次访问当前顶点的所有邻接点 if (eachFile.isFile()) {//标记这个邻接点已访问,是文件没有必要入队列 System.out.println("file:" + eachFile.getCanonicalPath()); } else {//标记这个邻接点已访问,是目录则入队列 System.out.println("dir--:" + eachFile.getCanonicalPath()); queue.offer(eachFile); } }//当前顶点所有邻接点访问完毕 }//队列为空退出 }
例二:迷宫问题
定义一个二维数组:
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
Input
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。
Output
左上角到右下角的最短路径,格式如样例所示。
Sample Input
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
Sample Output
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)
import java.util.*; public class Main{ private Point cur,next;//当前顶点及它的邻接点 private Point record[][];//用来记录路径 private int dir[][]={{0,1},{1,0},{0,-1},{-1,0}};//沿四个方向,右,下,左,上 private int mark[][]; //迷宫数组 public Main(int mark[][]){//构造函数 this.mark=mark; record=new Point[5][5]; for(int i=0;i< 5;i++) for(int j=0;j< 5;j++) record[i][j]=new Point(); cur=new Point(); next=new Point(); } public void bfs(){ //广度优先搜索迷宫 int i; Queue<Point> qu=new LinkedList<Point>(); cur.x=0; cur.y=0; qu.offer(cur); //起点入队 mark[0][0]=1; //标记为已访问 while(!qu.isEmpty()) { //队列非空 cur=qu.poll(); //队列头节点出队,当前节点 //访问当前节点的所有邻接点,可能有四个,沿四个方向,右,下,左,上 for(i=0;i<4;i++){ next.x=cur.x+dir[i][0]; next.y=cur.y+dir[i][1]; if(next.x==4&&next.y==4){//如果是出口 record[next.x][next.y].x=cur.x; //这个节点存上个节点的坐标 record[next.x][next.y].y=cur.y; return; } if(next.x>=0&&next.x<5&&next.y>=0&&next.y<5&&mark[next.x][next.y]==0){ //如果是邻接点 //这个节点存上个节点的坐标 record[next.x][next.y].x=cur.x; //这个节点存上个节点的坐标 record[next.x][next.y].y=cur.y; mark[next.x][next.y]=1; //标记此邻接点已访问 qu.offer(new Point(next.x,next.y)); //入队 } }//当前点的所有邻接点访问完毕 } //队列为空 } public void print(){ Point point[]=new Point[50]; int i=4;int j=4;int k=0; int m=0;int n=0; while(i!=0||j!=0)/////把得到的记录record[][]存起来 { m=i;n=j; point[k]=record[m][n]; i=record[m][n].x; j=record[m][n].y; k++; } for(i=k-1;i>=0;i--)/////////////逆序输出 System.out.printf("(%d, %d)\n",point[i].x,point[i].y); System.out.printf("(4, 4)\n");////最后要打印的,之前没记录它 } public static void main(String[] args) { Scanner in=new Scanner(System.in); int[][] mark=new int[5][5]; for(int i=0;i< 5;i++) for(int j=0;j< 5;j++) mark[i][j]=in.nextInt(); Main m=new Main(mark); m.bfs(); m.print(); } } class Point { int x = 0; int y = 0; public Point() { this(0, 0); } public Point(int x, int y) { this.x = x; this.y = y; } public boolean equals(Point p) { return (x == p.x) && (y == p.y); } @Override public String toString() { return "(" + x + ", " + y + ")"; } }
下载源码