Java实现深度搜索DFS算法详解

Java实现深度搜索DFS算法详解

DFS简介

深度搜索(Depth First Search, DFS)是一种用于遍历或搜索树或图的算法。其基本思想是从根节点出发,尽可能深的遍历每一个节点,直到没有下一个未访问的节点,然后回溯到最近的未访问节点,并继续访问其它节点。

DFS算法流程

DFS算法的流程如下:

  1. 将起始节点添加到栈中
  2. 判断栈是否为空,如果为空则退出搜索
  3. 从栈中取出一个节点
  4. 判断该节点是否为目标节点,如果是则搜索结束
  5. 如果不是目标节点,则将所有与该节点相邻的未访问节点添加到栈中,并标记为已访问
  6. 回到步骤2

Java实现DFS算法

下面是一个Java实现DFS算法的示例,假设有一个图G和起始节点S:

import java.util.Stack;

public class DFS {
    public static void main(String[] args) {
        Graph graph = new Graph(6);
        graph.addEdge(0, 1);
        graph.addEdge(0, 2);
        graph.addEdge(1, 2);
        graph.addEdge(2, 3);
        graph.addEdge(3, 4);
        graph.addEdge(4, 2);
        graph.addEdge(4, 5);
        dfs(graph, 0);
    }

    public static void dfs(Graph graph, int startNode) {
        boolean[] visited = new boolean[graph.nodes.length];
        Stack<Integer> stack = new Stack<>();
        stack.push(startNode);
        visited[startNode] = true;
        while (!stack.empty()) {
            int currentNode = stack.pop();
            System.out.print(currentNode + " ");
            for (int i = 0; i < graph.nodes[currentNode].size(); i++) {
                int nextNode = graph.nodes[currentNode].get(i);
                if (!visited[nextNode]) {
                    stack.push(nextNode);
                    visited[nextNode] = true;
                }
            }
        }
    }
}

class Graph {
    int v;
    LinkedList<Integer>[] nodes;

    public Graph(int v) {
        this.v = v;
        nodes = new LinkedList[v];
        for (int i = 0; i < v; i++) {
            nodes[i] = new LinkedList<>();
        }
    }

    public void addEdge(int start, int end) {
        nodes[start].add(end);
    }
}

上述代码中定义了一个Graph类,用于存储节点和边的信息。dfs方法中的visited数组用于记录节点是否被访问过,stack用于存储遍历的节点,startNode为起点。

执行结果为:0 2 3 4 5 1。从起始节点0开始遍历,先访问0,然后将与0相邻且未访问节点2加入栈,此时栈为[2],继续访问2,将与2相邻且未访问节点3和4加入栈,此时栈为[4, 3],访问4,将与4相邻且未访问节点5加入栈,此时栈为[3, 5],依次访问节点5、节点3,发现没有未访问节点,返回到节点2,将与2相邻且未访问节点1加入栈,此时栈为[1],访问节点1并结束搜索。

下面是另一个示例,假设有一个迷宫图maze:

import java.util.Arrays;

public class DFS {
    public static void main(String[] args) {
        int[][] maze = {
                {1, 1, 1, 1, 1, 1, 1, 1, 1},
                {1, 0, 1, 0, 0, 0, 0, 0, 1},
                {1, 0, 1, 1, 1, 0, 1, 0, 1},
                {1, 0, 0, 0, 1, 0, 1, 0, 1},
                {1, 0, 1, 1, 1, 0, 1, 0, 1},
                {1, 0, 1, 0, 0, 0, 1, 0, 1},
                {1, 0, 1, 1, 1, 1, 1, 0, 1},
                {1, 0, 0, 0, 0, 0, 0, 0, 1},
                {1, 1, 1, 1, 1, 1, 1, 1, 1}
        };
        dfs(maze, 1, 1, 7, 7);
    }

    public static void dfs(int[][] maze, int startX, int startY, int endX, int endY) {
        int[][] visited = new int[maze.length][maze[0].length];
        for (int[] row : visited) Arrays.fill(row, -1);

        Stack<Point> stack = new Stack<>();
        stack.push(new Point(startX, startY));
        visited[startX][startY] = 0;

        int[][] direction = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

        while (!stack.empty()) {
            Point currentPoint = stack.pop();
            for (int i = 0; i < 4; i++) {
                int nextX = currentPoint.x + direction[i][0];
                int nextY = currentPoint.y + direction[i][1];
                if (nextX < 0 || nextY < 0 || nextX >= maze.length || nextY >= maze[0].length) continue;
                if (maze[nextX][nextY] == 1 || visited[nextX][nextY] != -1) continue;
                visited[nextX][nextY] = visited[currentPoint.x][currentPoint.y] + 1;
                stack.push(new Point(nextX, nextY));
            }
        }

        System.out.println(visited[endX][endY]);
    }

    static class Point {
        int x;
        int y;

        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
}

上述代码中定义了一个Point类,用于存储x,y的坐标信息,这是一个典型的迷宫问题。执行结果为:22。

从起点(1,1)开始遍历,先访问(1,1),然后将与(1,1)相邻且未访问的点(2,1)、(1,2)加入栈,此时栈为[(2,1),(1,2)],访问(2,1),将与(2,1)相邻且未访问的点(3,1)加入栈,此时栈为[(1,2),(3,1)],继续访问(1,2),将(1,3)加入栈,此时栈为[(3,1),(1,3)],访问(3,1),将(4,1)加入栈,此时栈为[(1,3),(4,1)],依次访问(1,3)、(4,1)、(5,1)、(6,1)、(6,2)、(6,3)、(6,4)、(5,4)、(4,4)、(3,4)、(2,4)、(2,3)、(2,2)、(3,2)、(3,3)、(4,3)、(5,3)、(5,2)、(4,2)、(4,3)、(4,4)、(5,4)、(6,4)、(6,5)、(6,6)、(5,6)、(4,6)、(3,6)、(2,6)、(1,6)、(1,7)、(2,7)、(3,7)、(4,7)、(5,7)、(6,7)、(7,7)、(7,6)、(7,5)、(7,4)、(7,3)、(7,2)、(7,1),发现已到达终点(7,7),返回22。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java实现深度搜索DFS算法详解 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • Spring Boot 入门教程

    SpringBoot入门教程 SpringBoot是一个快速开发、轻量级、微服务框架,它简化了Spring应用的开发过程,提供了自动化配置、可插拔的组件和简化的XML配置等特点,使得SpringBoot成为当前企业级Java应用开发的主流框架之一。本教程旨在帮助读者从入门到掌握SpringBoot,实现快速且高效的应用开发。 环境搭建 在开始使用Spring…

    Java 2023年5月15日
    00
  • Java数组常见应用详解【创建、遍历、排序、查找】

    Java数组常见应用详解 数组是一种非常常见的数据结构,它可以用于存储一组数据,并且支持快速的遍历、排序和查找等操作。在Java中,数组是一个容器对象,可以存储相同类型的元素,并且在创建后其大小是不可改变的。本文将详细介绍Java数组的创建、遍历、排序和查找等常见应用,让大家对Java数组有更深入的了解。 创建数组 在Java中,可以通过以下方式来创建数组:…

    Java 2023年5月26日
    00
  • 浅谈Java springboot日志管理

    浅谈Java Spring Boot日志管理 作为 Java 程序员,我们使用日志来记录程序运行过程中的状态信息和错误信息。Spring Boot 提供了使用很方便的日志处理方式。在本文中,我们将介绍如何在 Spring Boot 项目中管理日志。 添加日志依赖 Spring Boot 自带日志框架,常用的是 logback 和 log4j2。如果你想使用其…

    Java 2023年5月19日
    00
  • 基于spring boot 的配置参考大全(推荐)

    下面就来详细讲解一下“基于Spring Boot的配置参考大全(推荐)”的完整攻略。 1. 基本介绍 “基于Spring Boot的配置参考大全(推荐)”是一篇非常全面的配置攻略,旨在帮助Spring Boot开发者更好地了解和掌握Spring Boot的配置方式。该文件包含了以下内容: Spring Boot配置文件的基本语法和命名规则 常用的配置方式,包…

    Java 2023年5月15日
    00
  • 关于mysql时间区间问题浅析

    下面是关于“关于mysql时间区间问题浅析”的完整攻略。 1. 问题的提出 在mysql中处理时间区间问题常常会遇到一些困难,例如当需要查询最近一周、一个月或一年的数据时,应该如何正确的处理时间范围? 2. 解决方法 2.1 使用范围查询 查询一天内的数据可以用如下语句: SELECT * FROM table_name WHERE create_time …

    Java 2023年5月20日
    00
  • SpringBoot应用启动内置Tomcat的过程源码分析

    下面我将为您详细讲解“SpringBoot应用启动内置Tomcat的过程源码分析”。 SpringBoot应用启动流程 SpringBoot能够提供如此简单易用的开发体验,离不开对应用启动过程的封装和自动配置。下面是SpringBoot应用启动的大体流程: SpringBoot启动类加载:在启动类的main方法中触发SpringApplication.run…

    Java 2023年5月19日
    00
  • Java实现二叉树的深度优先遍历和广度优先遍历算法示例

    针对“Java实现二叉树的深度优先遍历和广度优先遍历算法示例”的题目,下面给出完整的攻略。 什么是二叉树深度优先遍历和广度优先遍历 在学习Java实现二叉树深度优先遍历和广度优先遍历之前,我们需要先了解什么是二叉树深度优先遍历和广度优先遍历。 二叉树深度优先遍历是先访问根节点,再遍历左子树,最后再遍历右子树。而广度优先遍历则是一层一层地访问树节点,即先访问第…

    Java 2023年5月19日
    00
  • Java实现万年历效果

    下面是“Java实现万年历效果”的完整攻略。 准备工作 在实现万年历之前,需要先了解一些基本知识: Java 的日期类 Date、Calendar 和 LocalDate Java 的输入输出流,包括 Scanner 和 System.out Java 的字符串拼接和格式化输出 模块化编程及测试方法 实现步骤 接下来就可以开始实现万年历了。 步骤1:获取用户…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部