深度優先搜索(DFS)完全解析:從原理到 Java 實戰

深度優先搜索(DFS)完全解析:從原理到 Java 實戰

@TOC
作為一名程序員,你是否遇到過需要在復雜的圖結構中尋找路徑、檢測環,或者進行樹遍歷的問題?深度優先搜索(Depth-First Search, DFS)作為一種經典的圖遍歷算法,能夠輕松應對這些場景。在 CSDN 社區中,技術文章的受歡迎程度往往取決于內容的實用性、代碼的可讀性以及圖文結合的講解方式。因此,本文將為你帶來一篇深入淺出、圖文并茂、代碼詳盡的 DFS 指南,涵蓋原理、Java 實現、應用場景和實戰示例,確保你不僅理解 DFS,還能立刻上手應用!


什么是深度優先搜索(DFS)?

深度優先搜索(DFS)是一種用于遍歷或搜索樹或圖的算法。它的核心思想是:從一個起始節點開始,沿著一條路徑盡可能深入地探索,直到無法繼續前進時,再回溯到上一個分叉點,嘗試其他路徑。用一句話概括:DFS 是一種“先走到盡頭再回頭”的搜索策略

與廣度優先搜索(BFS)“層層擴展”的方式不同,DFS 更像是一個勇敢的探險家,優先深入某一條路,直到碰壁才返回。這種特性使得 DFS 在某些問題(如路徑查找、環檢測)中特別高效。


DFS 的工作原理(圖解)

為了讓你直觀理解 DFS 的執行過程,我們以一個簡單的圖為例:

圖結構:0/ \1---2|3
  • 邊表示:0-1, 0-2, 1-2, 2-3
  • DFS 從節點 0 開始
    1. 訪問 0
    2. 從 0 進入 1,訪問 1
    3. 從 1 進入 2,訪問 2
    4. 從 2 進入 3,訪問 3
    5. 3 沒有未訪問的鄰居,回溯到 2
    6. 2 沒有其他未訪問鄰居,回溯到 1
    7. 1 沒有其他未訪問鄰居,回溯到 0
    8. 0 的所有鄰居已訪問,結束

訪問順序:0 -> 1 -> 2 -> 3

下圖展示了 DFS 的過程(灰色表示已訪問):

初始狀態       訪問 0        訪問 1        訪問 2        訪問 30            0*           0*           0*           0*/ \          / \          / \          / \          / \1---2        1---2        1*--2        1*--2*       1*--2*|            |            |            |            |3            3            3            3*           3*

這種“一條路走到黑”的方式,正是 DFS 的精髓。


DFS 的應用場景

DFS 在實際開發中用途廣泛,以下是幾個典型場景:

  1. 路徑查找:在迷宮或圖中尋找從起點到終點的所有可能路徑。
  2. 環檢測:判斷圖中是否存在環,常用于依賴關系分析。
  3. 拓撲排序:對有向無環圖(DAG)進行排序,例如任務調度。
  4. 連通性分析:在無向圖中找出所有連通分量。
  5. 樹遍歷:實現二叉樹的先序、中序、后序遍歷。

用 Java 實現 DFS

在 Java 中,DFS 通常通過遞歸顯式棧實現。這里我們以鄰接表表示圖,并用遞歸方式實現 DFS,因為它代碼簡潔且符合直覺。

完整代碼示例

以下是一個基于鄰接表的 DFS 實現,包含詳細注釋:

import java.util.*;public class DFSGraph {private int V; // 圖的節點數private LinkedList<Integer>[] adj; // 鄰接表表示圖// 構造函數,初始化圖public DFSGraph(int v) {V = v;adj = new LinkedList[v];for (int i = 0; i < v; i++) {adj[i] = new LinkedList<>(); // 為每個節點初始化鄰接表}}// 添加邊(無向圖)public void addEdge(int v, int w) {adj[v].add(w); // v -> wadj[w].add(v); // w -> v(無向圖需添加雙向邊)}// DFS 核心遞歸方法private void dfsUtil(int v, boolean[] visited) {visited[v] = true; // 標記當前節點為已訪問System.out.print(v + " "); // 訪問節點(這里打印)// 遍歷當前節點的所有鄰接節點for (int neighbor : adj[v]) {if (!visited[neighbor]) { // 如果鄰接節點未被訪問dfsUtil(neighbor, visited); // 遞歸訪問}}}// DFS 入口方法public void DFS(int start) {boolean[] visited = new boolean[V]; // 記錄訪問狀態dfsUtil(start, visited); // 從起始節點開始 DFS}// 測試代碼public static void main(String[] args) {DFSGraph graph = new DFSGraph(5); // 創建一個 5 個節點的圖// 添加邊graph.addEdge(0, 1);graph.addEdge(0, 2);graph.addEdge(1, 3);graph.addEdge(2, 4);graph.addEdge(3, 4);System.out.println("從節點 0 開始的 DFS 遍歷:");graph.DFS(0);}
}

運行結果

從節點 0 開始的 DFS 遍歷:
0 1 3 4 2

代碼詳解

  1. 圖的表示
    • 使用 LinkedList<Integer>[] adj 作為鄰接表,adj[i] 存儲節點 i 的所有鄰接節點。
    • V 表示節點總數。
  2. 添加邊
    • addEdge 方法為無向圖添加雙向邊。
  3. DFS 實現
    • dfsUtil 是遞歸核心,標記并訪問當前節點,然后遞歸處理未訪問的鄰接節點。
    • DFS 方法初始化 visited 數組并啟動遍歷。
  4. main 方法
    • 構建一個 5 節點圖,添加邊后從節點 0 開始 DFS。

DFS 的時間與空間復雜度

  • 時間復雜度:O(V + E)
    • V 是節點數,E 是邊數,DFS 需要訪問所有節點和邊。
  • 空間復雜度:O(V)
    • 遞歸棧的深度最多為 V,加上 visited 數組的空間。

實戰項目:迷宮求解

讓我們通過一個迷宮問題展示 DFS 的應用。假設有一個 4x4 的迷宮,0 表示通路,1 表示墻,目標是從 (0,0) 到 (3,3) 找一條路徑。

迷宮表示

0 1 0 0
0 1 0 1
0 0 0 0
1 1 0 0

Java 代碼

public class MazeSolver {static int[][] maze = {{0, 1, 0, 0},{0, 1, 0, 1},{0, 0, 0, 0},{1, 1, 0, 0}};static int N = 4;static int[][] path = new int[N][N]; // 記錄路徑// 四個方向:上、右、下、左static int[] dx = {-1, 0, 1, 0};static int[] dy = {0, 1, 0, -1};public static boolean solveMaze(int x, int y) {// 到達終點 (3,3)if (x == N - 1 && y == N - 1) {path[x][y] = 1;return true;}// 檢查當前位置是否合法if (isSafe(x, y)) {path[x][y] = 1; // 標記為路徑的一部分// 嘗試四個方向for (int i = 0; i < 4; i++) {int nextX = x + dx[i];int nextY = y + dy[i];if (solveMaze(nextX, nextY)) {return true;}}// 回溯:如果當前路徑不通,撤銷標記path[x][y] = 0;}return false;}// 檢查坐標是否有效public static boolean isSafe(int x, int y) {return x >= 0 && x < N && y >= 0 && y < N && maze[x][y] == 0;}public static void main(String[] args) {if (solveMaze(0, 0)) {System.out.println("找到路徑:");for (int i = 0; i < N; i++) {for (int j = 0; j < N; j++) {System.out.print(path[i][j] + " ");}System.out.println();}} else {System.out.println("無解");}}
}

輸出結果

找到路徑:
1 0 0 0
1 0 0 0
1 1 1 1
0 0 0 1

解析

  • DFS 策略:從 (0,0) 開始,嘗試四個方向(上、右、下、左),遇到墻或邊界回溯。
  • 路徑記錄path 數組標記走過的位置,成功到達 (3,3) 時返回路徑。

總結與互動

通過這篇文章,你應該已經掌握了 DFS 的原理、Java 實現以及實戰應用。無論是圖遍歷還是迷宮求解,DFS 都展現了其簡潔而強大的能力。為了加深理解,不妨試試以下問題:

  • 如何用 DFS 檢測圖中的環?

  • 如果用棧而非遞歸實現 DFS,會是什么樣?

    歡迎在評論區分享你的代碼或疑問,一起探討 DFS 的更多玩法!如果覺得這篇博客對你有幫助,記得點贊和收藏哦!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/72962.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/72962.shtml
英文地址,請注明出處:http://en.pswp.cn/web/72962.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【人工智能】如何理解transformer中的token?

如何理解transformer中的token? **一、Token在Transformer中的作用****二、文本分詞的常見方法****1. 基于詞典的分詞&#xff08;Dictionary-based Tokenization&#xff09;****2. 子詞分詞&#xff08;Subword Tokenization&#xff09;****(1) WordPiece算法****(2) BPE&a…

AI風向標《AI與視頻制作全攻略:從入門到精通實戰課程》

課程信息 AI風向標《AI與視頻制作全攻略&#xff1a;從入門到精通實戰課程》,夸克網盤和百度網盤課程。 課程介紹 《AI與視頻制作全攻略&#xff1a;從入門到精通實戰課程》是一套全面融合AI技術與視頻制作的實戰課程&#xff0c;旨在幫助創作者從基礎軟件使用到高級視頻剪輯…

mayfly-go開源的一站式 Web 管理平臺

mayfly-go 是一款開源的一站式 Web 管理平臺&#xff0c;旨在通過統一的界面簡化 Linux 服務器、數據庫&#xff08;如 MySQL、PostgreSQL、Redis、MongoDB 等&#xff09;的運維管理。以下從多個維度對其核心特性、技術架構、應用場景及生態進行詳細解析&#xff1a; 一、核心…

車輛模型——運動學模型

文章目錄 約束及系統移動機器人運動學模型&#xff08;Kinematic Model&#xff09;自行車模型含有加速度 a a a 的自行車模型系統偏差模型 在機器人的研究領域中&#xff0c;移動機器人的系統建模與分析是極為關鍵的基礎環節&#xff0c;本文以非完整約束的輪式移動機器人為研…

go命令使用

查看配置信息 go env配置go國內源 export GO111MODULEon export GOPROXYhttps://goproxy.cn測試 go install github.com/jesseduffield/lazydockerlatesthttps://github.com/jesseduffield/lazydocker

Chrome-Edge-IDEA-Win 常用插件-工具包

Chrome-Edge-IDEA-Win 常用插件-工具包 Chrome-Edge-IDEA-Win 常用插件-工具包谷歌插件chropathJSONViewOctotree - GitHub code treeXPath Helper書簽側邊欄篡改猴Print Edit WEEdge瀏覽器插件IDEA插件CodeGlance Pro 代碼迷你縮放圖插件Alibaba Cloud ToolkitAlibaba Java Co…

西門子V90伺服系統介紹

深入淺出地了解V90伺服驅動系統的核心特性和優勢&#xff0c;掌握其自動優化功能&#xff0c;使設備獲得更高的動態性能&#xff1b;同時&#xff0c;了解其自動抑制機械諧振頻率的特性&#xff0c;有助于在實際應用中減少機械振動和噪音。 方便快捷地熟悉V90的使用方式。通過伺…

【FastGPT】利用知識庫創建AI智能助手

【FastGPT】利用知識庫創建AI智能助手 摘要創建知識庫上傳文檔創建應用準備提示詞準備開場白關聯知識庫AI回答效果 摘要 關于FastGPT的部署&#xff0c;官方提供了docker-compose方式的部署文檔&#xff0c;如果使用的是podman和podman-compose的同學&#xff0c;可以參考這篇…

最新!Ubuntu Docker 安裝教程

源自: AINLPer&#xff08;每日干貨分享&#xff01;&#xff01;&#xff09; 編輯: ShuYini 校稿: ShuYini 時間: 2025-3-1 更多&#xff1a;>>>>大模型/AIGC、學術前沿的知識分享&#xff01; 看到很多部署大模型的時候&#xff0c;都是基于docker安裝部署的。…

html5炫酷3D立體文字效果實現詳解

炫酷3D立體文字效果實現詳解 這里寫目錄標題 炫酷3D立體文字效果實現詳解項目概述技術實現要點1. 基礎布局設置2. 動態背景效果3. 文字漸變效果4. 立體陰影效果5. 懸浮動畫效果 技術難點及解決方案1. 文字漸變動畫2. 立體陰影效果3. 性能優化 瀏覽器兼容性總結 項目概述 在這個…

電腦如何設置幾分鐘后自動關機

摘要&#xff1a;本文提供Windows、macOS和Linux系統設置定時自動關機的詳細方法。 目錄 一、Windows系統設置方法 設置定時關機 取消關機計劃 二、macOS系統設置方法 設置定時關機取消關機計劃 三、Linux系統設置方法 設置定時關機 取消關機計劃 四、注意事項五、擴展&#x…

Android音視頻多媒體開源庫基礎大全

從事音視頻開發工作&#xff0c;需要了解哪些常見的開源庫&#xff0c;從應用到底軟系統&#xff0c;整理了九大類&#xff0c;這里一次幫你總結完。 包含了應用層的MediaRecorder、surfaceView&#xff0c;以及常見音視頻處理庫FFmpeg和OpenCV&#xff0c;還有視頻渲染和音頻…

若依前端框架增刪改查

1.下拉列表根據數據庫加載 這個是用來查詢框 綁定了 change 事件來處理站點選擇變化后的查詢邏輯。 <el-form-item label"站點選擇" prop"stationId" v-has-permi"[ch:m:y]"><el-select v-model"queryParams.stationId" pl…

Java 第十一章 GUI編程(3)

目錄 內部類 內部類定義 內部類的特點 匿名內部類 格式&#xff1a; 內部類的意義 實例 內部類 ● 把類定義在另一個類的內部&#xff0c;該類就被稱為內部類。 ● 如果在類 Outer 的內部再定義一個類 Inner&#xff0c;此時類 Inner 就稱為內部類 &#xff08;或稱為嵌…

Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多變量回歸預測

Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多變量回歸預測 目錄 Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多變量回歸預測預測效果基本介紹程序設計參考資料 預測效果 基本介紹 Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多變量回歸預…

3DMAX曲線生成器插件CurveGenerator使用方法

1. 腳本功能簡介 3DMAX曲線生成器插件CurveGenerator是一個用于 3ds Max 的樣條線生成工具&#xff0c;用戶可以通過簡單的UI界面輸入參數&#xff0c;快速生成多條樣條線。每條樣條線的高度值隨機生成&#xff0c;且可以自定義以下參數&#xff1a; 頂點數量&#xff1a;每條…

LiteratureReading:[2023] GPT-4: Technical Report

文章目錄 一、文獻簡明&#xff08;zero&#xff09;二、快速預覽&#xff08;first&#xff09;1、標題分析2、作者介紹3、引用數4、摘要分析&#xff08;1&#xff09;翻譯&#xff08;2&#xff09;分析 5、總結分析&#xff08;1&#xff09;翻譯&#xff08;2&#xff09;…

vm_pwn入門 -- [GHCTF 2025]my_vm

先看基本邏輯 int __fastcall main(int argc, const char **argv, const char **envp) {unsigned __int16 IP; // [rspCh] [rbp-14h] BYREFunsigned __int16 SP; // [rspEh] [rbp-12h] BYREFunsigned __int16 cmd_count; // [rsp10h] [rbp-10h] BYREFunsigned __int16 i; // [r…

CA 機構如何防止中間人攻擊

在現代互聯網中&#xff0c;中間人攻擊&#xff08;Man-in-the-Middle Attack&#xff0c;簡稱 MITM&#xff09;是一種常見的網絡攻擊方式&#xff0c;攻擊者通過攔截和篡改通信雙方的信息&#xff0c;進而竊取敏感數據或執行惡意操作。為了防止中間人攻擊&#xff0c;證書頒發…

Elasticsearch快速上手與深度進階:一站式實戰教程

目錄 1. Elasticsearch 簡介 2. 安裝與啟動 方式 1&#xff1a;Docker 快速安裝&#xff08;推薦&#xff09; 方式 2&#xff1a;手動安裝 3. 基礎操作 3.1 創建索引 3.2 插入文檔 3.3 查詢文檔 3.4 更新文檔 3.5 刪除文檔 4. 高級查詢 4.1 布爾查詢 4.2 范圍查詢…