java实现DFS求路径是否有解问题

今天回顾了DFS——Depth First Search——深度优先遍历,这个算法主要有两个用途:一是用于对于未知解的探索,一个典型的例子是走迷宫,也就是我们要列出所有的可能性来穷举,如果找到一条可行之路那么说明我们要解决的问题有戏,如果到最后也没有找到一条可行之路,那么说明我们的问题没有解。二是作为拓扑排序的基石,这一点我们以后再讲。

那么如何来实现DFS算法呢? 我们需要的原料有:结点、边、结点数、以及一个很重要的标记数组——来标记某个结点是否已经被访问过了,这可以避免我们在图中来来回回鬼打墙。

public class DFS {

	private char[] vertices;
	private int verticeNum;
	private boolean[] isVisited;
	private int[][] edges;

第二步我们通过这个类的一个有参构造函数初始化一下这些原始材料。

public DFS(int n) {
		vertices = new char[n];
		verticeNum = n;
		isVisited = new boolean[n];
		for(int i = 0; i<n;i++){
			isVisited[i] = false;
			
		}
		edges = new int[n][n];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				edges[i][j] = 0;
				
			}
		}
	}

第三步,我们实现加边、加点、访问结点的函数封装,为后续代码的简洁直观打基础

public void addEdge(int i,int j){
		  //避免加入起点和终点相同的边,其实也就是一个点了……
		if(i==j)
			return;
		edges[i][j] = 1;
		edges[j][i] = 1;
		
	}
	
public void setVertices(char[] vertices){
		this.vertices = vertices;
	}
public void visit(int i){
		System.out.print(vertices[i] + " ");
	}



第四步,是一个很重要很核心的递归函数,基本思想就是,深度访问到某一个结点时,访问它并将之标记为已访问。然后在所有的结点中,找这个结点的未访问过的邻结点(也就是和这个结点 由边连接的结点),对邻接点进行深度上的访问。

public void traverse(int i){
		isVisited[i] = true;
		visit(i);
		for(int j = 0; j<verticeNum;j++){
			if(edges[i][j] ==1 && isVisited[j] ==false){
				traverse(j);
			}
		}
		
	}
第五步,在DFS算法的主方法中对图中的每一个结点进行遍历。 我们可以看到,DFSTraverse 函数对每一个结点调用递归函数traverse,traverse函数中有有用到visit函数的地方,我觉得这种封装很棒。

	public void DFSTraverse(){
		for(int i = 0; i< verticeNum;i++){
			if(!isVisited[i] )
				traverse(i);
		}
	}
最后,在main函数中实例化,用例子来试一下。

public static void main(String[] args) {
		
		DFS g = new DFS(9);
		char[] vertices = {'A','B','C','D','E','F','G','H','I'};
		
		g.setVertices(vertices);

        g.addEdge(0, 1);
        g.addEdge(0, 5);
        g.addEdge(1, 0);
        g.addEdge(1, 2);
        g.addEdge(1, 6);
        g.addEdge(1, 8);
        g.addEdge(2, 1);
        g.addEdge(2, 3);
        g.addEdge(2, 8);
        g.addEdge(3, 2);
        g.addEdge(3, 4);
        g.addEdge(3, 6);
        g.addEdge(3, 7);
        g.addEdge(3, 8);
        g.addEdge(4, 3);
        g.addEdge(4, 5);
        g.addEdge(4, 7);
        g.addEdge(5, 0);
        g.addEdge(5, 4);
        g.addEdge(5, 6);
        g.addEdge(6, 1);
        g.addEdge(6, 3);
        g.addEdge(6, 5);
        g.addEdge(6, 7);
        g.addEdge(7, 3);
        g.addEdge(7, 4);
        g.addEdge(7, 6);
        g.addEdge(8, 1);
        g.addEdge(8, 2);
        g.addEdge(8, 3);

       System.out.print("深度优先遍历(递归):");
       g.DFSTraverse();
}
我们可以得到结果:深度优先遍历(非递归):A B C D E F G H I 

PS:附赠非递归DFS实现。

其基本思想就是,用到栈,利用栈后进先出的结构特点,每弹出一个结点,就将此结点的未访问过的邻结点放入栈,这样下次从栈中取出的就是往深处走的邻结点,当走到头的时候再取出来的结点就是返回遇到的第一个分岔路口了。

public void DFSNoRecurion(){
		Stack<Integer> stack = new Stack<Integer>();
		for(int i = 0; i< verticeNum;i++){
			
			if(!isVisited[i] ){
				
				stack.push(i);
				do{
				
					int cur = stack.pop();
					if(!isVisited[cur]){
						visit(cur);
						isVisited[cur] = true;
						
						for(int j =0;j < verticeNum;j++){
							if(edges[cur][j] ==1 && !isVisited[j]){
								stack.push(j);
								break;
							}
						}
					}
				}while(!stack.isEmpty());
				
				
				
			}
			
			
		}
	}








可以使用以下代码实现 Java 中的 DFS 输出路径: ```java import java.util.*; public class Main { static int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 上下左右四个方向 static int n, m; static int[][] matrix; static boolean[][] visited; static List<int[]> path = new ArrayList<>(); // 存储路径 public static void main(String[] args) { Scanner sc = new Scanner(System.in); n = sc.nextInt(); m = sc.nextInt(); matrix = new int[n][m]; visited = new boolean[n][m]; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { matrix[i][j] = sc.nextInt(); } } dfs(0, 0); } public static void dfs(int x, int y) { if (x < 0 || x >= n || y < 0 || y >= m || visited[x][y] || matrix[x][y] == 0) { return; } visited[x][y] = true; path.add(new int[]{x, y}); // 添加当前节点到路径中 if (x == n - 1 && y == m - 1) { // 到达终点,输出路径 for (int[] p : path) { System.out.print("(" + p[0] + "," + p[1] + ") "); } System.out.println(); } for (int[] dir : dirs) { int nx = x + dir[0]; int ny = y + dir[1]; dfs(nx, ny); } path.remove(path.size() - 1); // 回溯,从路径中删除当前节点 visited[x][y] = false; } } ``` 这段代码实现了一个简单的 DFS,用于输出从左上角到右下角的路径。其中 `matrix` 数组表示迷宫,0 表示障碍物,1 表示可以通过的路。`visited` 数组用于记录节点是否被访问过,`path` 列表用于存储路径。在 DFS 中,如果当前节点是终点,则输出路径;否则,遍历当前节点的四个方向,递归调用 DFS。在回溯时,从路径中删除当前节点,将当前节点标记为未访问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值