数据结构-深度优先搜索Java实现

目录

一、引言

深度优先搜索(DFS)是一种在图或树中进行搜索的算法,它沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所有边都已探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。

DFS是一种盲目搜索,即它并不需要知道目标的位置,只是尽可能地遍历所有可能的路径。因此,它的搜索效率并不高,特别是在面对大规模数据时。然而,DFS可以找到目标值或解决目标问题,对于解决NP问题作用很大。

此外,DFS如同数据结构中的栈结构,是一种后进先出的结构,导致了所有的点进入栈时有一个顺序,我们称之为 "DFS序"。

二、算法步骤

深度优先搜索算法的步骤如下:

  1. 选取图中某一顶点Vi为出发点,访问并标记该顶点。
  2. 以Vi为当前顶点,依次搜索Vi的每个邻接点Vj,若Vj未被访问过,则访问和标记邻接点Vj,若Vj已被访问过,则搜索Vi的下一个邻接点。
  3. 以Vj为当前顶点,重复步骤2),直到图中和Vi有路径相通的顶点都被访问为止。
  4. 若图中尚有顶点未被访问过(非连通的情况下),则可任取图中的一个未被访问的顶点作为出发点,重复上述过程,直至图中所有顶点都被访问。

三、原理演示

递归实现

  1. 选择起始节点:从图中的一个起始节点开始,将该节点标记为已访问。
  2. 递归探索邻居节点:对于当前节点,遍历它的邻居节点。如果邻居节点尚未被访问,就递归地调用深度优先搜索函数,以此邻居节点为新的起始节点,重复步骤1。
  3. 回溯:当当前节点的所有邻居节点都被访问后,回溯到上一个节点,并继续遍历其未被访问的邻居节点。
  4. 重复步骤2和3,直到图中的所有节点都被访问。

下面是递归实现深度优先搜索的示例代码:

java 复制代码
public void dfsRecursive(Node node, Set<Node> visited) {
   visited.add(node);
   System.out.print(node.value + " ");
   
   for (Node neighbor : node.neighbors) {
       if (!visited.contains(neighbor)) {
           dfsRecursive(neighbor, visited);
       }
   }
}

非递归实现(使用堆栈)

  1. 选择起始节点:从图中的一个起始节点开始,将该节点标记为已访问,并将它入栈。
  2. 迭代遍历:使用一个循环,不断从栈中弹出节点,然后遍历它的邻居节点。
  3. 探索邻居节点:对于当前弹出的节点,遍历其邻居节点。如果邻居节点尚未被访问,就将其标记为已访问并将其入栈。
  4. 重复步骤2和3,直到栈为空。

下面是非递归实现深度优先搜索的示例代码:

java 复制代码
public void dfsIterative(Node start) {
   Stack<Node> stack = new Stack<>();
   Set<Node> visited = new HashSet<>();

   stack.push(start);
   visited.add(start);

   while (!stack.isEmpty()) {
       Node current = stack.pop();
       System.out.print(current.value + " ");
       
      for (Node neighbor : current.neighbors) {
          if (!visited.contains(neighbor)) {
               stack.push(neighbor);
               visited.add(neighbor);
           }
       }
   }
}

无论采用递归还是非递归方式,深度优先搜索的关键思想是深入到尽可能深的层级,直到无法再深入为止,然后回溯到上一个节点,继续探索。这一过程不断重复,直到遍历整个图。深度优先搜索对于解决路径查找、拓扑排序、连通性检测等问题都非常有用。

四、代码实战

以下是深度优先搜索算法的Java代码实现:

java 复制代码
import java.util.*;

public class DFS {
   private int V; // 顶点数量
   private LinkedList<Integer> adj[]; // 邻接表

   // 构造函数
   DFS(int v) {
       V = v;
       adj = new LinkedList[v];
       for (int i = 0; i < v; ++i) {
           adj[i] = new LinkedList();
       }
   }

   // 添加边
   void addEdge(int v, int w) {
       adj[v].add(w);
   }

   // DFS函数
   void DFSUtil(int v, boolean visited[]) {
       // 标记当前节点为已访问并输出该节点
       visited[v] = true;
       System.out.print(v + " ");

       // 递归访问与v节点相邻的未访问节点
       Iterator<Integer> i = adj[v].listIterator();
       while (i.hasNext()) {
           int n = i.next();
           if (!visited[n])
               DFSUtil(n, visited);
       }
   }

   // DFS函数
   void DFS(int v) {
       // 标记所有顶点为未访问状态
      boolean visited[] = new boolean[V];

       // 调用递归函数DFSUtil开始从顶点v进行DFS遍历
       DFSUtil(v, visited);
   }
}

五、结论

我们一起来总结一下:

深度优先搜索在计算机科学中有着广泛的应用,例如用于遍历树或图的结构、查找路径、解决优化问题等。它的优点在于空间复杂度相对较小,可以处理大规模的数据,同时可以避免搜索冗余的节点。然而,深度优先搜索也有其局限性,例如可能会陷入死循环或无法找到最优解,因此需要根据具体问题选择合适的算法进行优化。

点赞收藏,富婆包养✋✋

相关推荐
骄马之死4 小时前
SpringMVC + SpringBoot 核心知识点总结
java·spring boot·后端
Frostnova丶4 小时前
【算法笔记】数学知识
笔记·算法
吴可可1235 小时前
AutoCAD 2016与2014二次开发关键差异
算法
GoGeekBaird5 小时前
Anthropic技能"(Skills)的经验分享
后端
王码码20355 小时前
多台服务器怎么统一看状态?Beszel 轻量监控,搭起来不费事
运维·服务器·后端·安全·阿里云·接口·web
郑洁文6 小时前
基于Spring Boot的流浪动物救助网站
java·spring boot·后端·毕设·流浪动物救助
雨白6 小时前
哈希:以时间换空间的算法实战
算法
螺丝钉code6 小时前
JAVA项目 Claude code CLAUDE.md 到底应该怎么写
java·人工智能·claude code
指令集梦境7 小时前
Cursor + Spring Boot实战:从零写一个RESTful API
spring boot·后端·restful
啦啦啦啦啦zzzz7 小时前
数据结构:红黑树理论
数据结构·c++·红黑树