自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

算法系列之搜索算法-深度優(yōu)先搜索DFS

人工智能
DFS 是一種非常重要的圖遍歷算法,適用于許多場(chǎng)景。遞歸實(shí)現(xiàn)簡(jiǎn)單直觀,但可能會(huì)受到棧深度的限制;迭代實(shí)現(xiàn)則避免了這個(gè)問題,但代碼稍復(fù)雜一些。根據(jù)具體需求選擇合適的實(shí)現(xiàn)方式。

隨著每年"金三銀四"招聘季的到來,許多求職者開始積極備戰(zhàn)面試。在眾多面試環(huán)節(jié)中,機(jī)試往往是不可或缺的一環(huán),而算法能力更是機(jī)試考核的重點(diǎn)。為此,我們特別推出算法系列文章,幫助大家系統(tǒng)復(fù)習(xí)算法知識(shí)。今天,我們將首先探討搜索算法中的重要內(nèi)容——深度度優(yōu)先搜索(DFS)。

圖的介紹

圖(Graph)是一種非線性的數(shù)據(jù)結(jié)構(gòu),由頂點(diǎn)(Vertex)和邊(Edge)組成。如下圖所示

_20250219193211.jpg分類如下:

  • 無向圖(Undirected Graph):邊沒有方向,表示雙向關(guān)系。
  • 有向圖(Directed Graph):邊有方向,表示單向關(guān)系。
  • 加權(quán)圖(Weighted Graph):邊帶有權(quán)重。
  • 無權(quán)圖(Unweighted Graph):邊沒有權(quán)重。

深度優(yōu)先搜索(DFS, Depth-First Search)

深度優(yōu)先搜索和廣度優(yōu)先搜索一樣,都是對(duì)圖進(jìn)行搜索的算法,目的也都是從起點(diǎn)開始搜索,直到到達(dá)頂點(diǎn)。深度優(yōu)先搜索會(huì)沿著一條路徑不斷的往下搜索,直到不能夠在繼續(xù)為止,然后在折返,開始搜索下一條候補(bǔ)路徑。

DFS 可以借助于?;蛘邅韺?shí)現(xiàn)。棧具有”后進(jìn)先出(LIFO)”特性,可以是有?;蛘哌f歸來實(shí)現(xiàn)遍歷。其實(shí)現(xiàn)步驟如下:

  1. 訪問節(jié)點(diǎn):從起始節(jié)點(diǎn)開始,訪問當(dāng)前節(jié)點(diǎn)。
  2. 遞歸
  • 遞歸訪問鄰居:對(duì)于當(dāng)前節(jié)點(diǎn)的每一個(gè)未訪問過的鄰居節(jié)點(diǎn),遞歸地調(diào)用 DFS。
  • 回溯:當(dāng)沒有未訪問的鄰居時(shí),回溯到上一個(gè)節(jié)點(diǎn),繼續(xù)搜索其他路徑。
  • 使用 Stack 來模擬遞歸過程,每次從棧中彈出一個(gè)節(jié)點(diǎn)并訪問它,然后將未訪問的鄰居節(jié)點(diǎn)壓入棧中。

示例代碼如下:

/**
 * 深度優(yōu)先搜索示例
 */
public class DFSExample {
    // 定義圖的節(jié)點(diǎn)類
    static class Node {
        int value;
        List< Node> neighbors;

        public Node(int value) {
            this.value = value;
            this.neighbors = new ArrayList<>();
        }

        // 添加鄰接節(jié)點(diǎn)
        public void addNeighbor( Node neighbor) {
            this.neighbors.add(neighbor);
        }
    }

    /**
     * 方式一 :棧實(shí)現(xiàn)
     * dfs 函數(shù)
     * @param startNode
     */
    public static void dfs( Node startNode) {

        if(startNode == null ) return;
        // 使用隊(duì)列存儲(chǔ)待訪問的節(jié)點(diǎn)
        Stack<Node> stack = new Stack<>();

        // 使用HashSet記錄已訪問的節(jié)點(diǎn)
        Set<Node> visited = new HashSet<>();
        // 將起點(diǎn)加入棧并標(biāo)記為已訪問
        stack.push(startNode);
        visited.add(startNode);
        // 遍歷棧
        while (!stack.isEmpty()){
             Node currentNode = stack.pop();
            System.out.println(currentNode.value);
            // 遍歷當(dāng)前節(jié)點(diǎn)的所有鄰接節(jié)點(diǎn)
            for (Node neighbor : currentNode.neighbors) {
                // 如果鄰接節(jié)點(diǎn)未被訪問,則加入棧并標(biāo)記為已訪問
                if (!visited.contains(neighbor)) {
                    stack.add(neighbor);
                    visited.add(neighbor);
                }
            }
        }

    }
    //方式二:遞歸實(shí)現(xiàn)
    public static void sec( Node currentNode,Set<Node> visited) {

        // 標(biāo)記當(dāng)前節(jié)點(diǎn)為已訪問
        visited.add(currentNode);
        System.out.println(currentNode.value);
        // 遞歸訪問所有未訪問的鄰居節(jié)點(diǎn)
        for (Node neighbor : currentNode.neighbors) {
            if (!visited.contains(neighbor))
                sec(neighbor, visited);
        }
    }

    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        Node node1 = new  Node(1);
        Node node2 = new  Node(2);
        Node node3 = new  Node(3);
        Node node4 = new  Node(4);
        Node node5 = new  Node(5);
        Node node6 = new  Node(6);


        node1.addNeighbor(node2);
        node1.addNeighbor(node3);
        node1.addNeighbor(node5);

        node2.addNeighbor(node1);
        node2.addNeighbor(node3);
        node2.addNeighbor(node5);

        node3.addNeighbor(node1);
        node3.addNeighbor(node2);
        node3.addNeighbor(node4);
        node3.addNeighbor(node6);

        node4.addNeighbor(node3);
        node4.addNeighbor(node6);

        node5.addNeighbor(node2);
        node5.addNeighbor(node6);

        node6.addNeighbor(node3);
        node6.addNeighbor(node4);
        node6.addNeighbor(node5);
        //棧實(shí)現(xiàn)
        dfs(node1);
        System.out.println("+++++++++遞歸實(shí)現(xiàn)++++++++++++");
        //遞歸實(shí)現(xiàn)
        Set< Node> visited = new HashSet<>();
        sec(node1,visited);
    }
}

DFS的特點(diǎn)

  • 時(shí)間復(fù)雜度:O(V+E)
  • 空間復(fù)雜度:O(V)
  • 適用場(chǎng)景:連通性檢測(cè)、路徑查找、迷宮求解

DFS 示例題

以下列舉了一些機(jī)試題

廣播服務(wù)器

題目描述:給定一個(gè)大小為 N×N 的二維矩陣 matrix,表示 N 個(gè)服務(wù)器之間的連接情況。matrix[i][j] = 1 表示服務(wù)器i 和 j 直接連接,matrix[i][j] = 0 表示不直接連接。計(jì)算初始需要給幾臺(tái)服務(wù)器廣播,才能使每個(gè)服務(wù)器都收到廣播。 輸入:N 行,每行 N 個(gè)數(shù)字(0 或 1),表示 N×N 的二維矩陣。 輸出:需要廣播的服務(wù)器的數(shù)量。

示例一: 輸入: 

1 0 0 

0 1 0

 0 0 1 

輸出:3

示例二: 輸入: 

1 1 

1 1 

輸出:1

public class DFSServer {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String[] firstLine = scanner.nextLine().split(" ");
        int n = firstLine.length;
        //初始化二維數(shù)組
        int[][] matrix = new int[n][n];
        for (int i = 0; i < n; i++) {
            String[] line = i==0 ? firstLine:scanner.nextLine().split(" ");
            for (int j = 0; j < n; j++) {
                matrix[i][j] = Integer.parseInt(line[j]);
            }
        }
        //初始化標(biāo)記數(shù)組
        int[] check = new int[n];
        //需要廣播的服務(wù)器的數(shù)量
        int ans = 0;
        Stack<Integer> stack = new Stack<>();
        // 遍歷每個(gè)服務(wù)器
        for (int i = 0; i < n; i++) {
            // 如果服務(wù)器 i 沒有被訪問過,就以它為起點(diǎn)進(jìn)行 DFS
            if (check[i] == 0) {
                ans++; // 新的連通分量,計(jì)數(shù)器加 1
                stack.add(i); // 將當(dāng)前服務(wù)器加入棧
                check[i] = 1; // 標(biāo)記為已訪問

                // 開始 DFS
                while (!stack.isEmpty()) {
                    // 彈出當(dāng)前服務(wù)器
                    int cur = stack.pop();
                    // 遍歷所有服務(wù)器,找到與 cur 相連且未訪問的服務(wù)器
                    for (int j = 0; j < n; j++) {
                        if (j != cur && matrix[cur][j] == 1 && check[j] == 0) {
                            // 將未訪問的服務(wù)器加入棧
                            stack.push(j);
                            // 將未訪問的服務(wù)器加入棧
                            check[j] = 1;
                        }
                    }
                }
            }
        }

        System.out.println(ans);

    }
}

總結(jié)

DFS 是一種非常重要的圖遍歷算法,適用于許多場(chǎng)景。遞歸實(shí)現(xiàn)簡(jiǎn)單直觀,但可能會(huì)受到棧深度的限制;迭代實(shí)現(xiàn)則避免了這個(gè)問題,但代碼稍復(fù)雜一些。根據(jù)具體需求選擇合適的實(shí)現(xiàn)方式。

責(zé)任編輯:武曉燕 來源: 修己xj
相關(guān)推薦

2021-04-28 07:59:21

深度優(yōu)先搜索

2020-10-17 11:14:19

數(shù)據(jù)結(jié)構(gòu)與算法系列

2012-02-29 13:32:28

Java

2023-05-30 07:58:01

谷歌搜索算法

2017-03-20 13:09:33

Swift廣度優(yōu)先搜索手游開發(fā)

2018-10-12 15:15:45

電商搜索算法

2019-03-29 09:40:38

數(shù)據(jù)結(jié)構(gòu)算法前端

2012-08-24 09:16:53

App Store

2023-04-14 08:07:20

數(shù)據(jù)結(jié)構(gòu)算法搜索

2013-04-23 09:31:52

SQL Server

2021-09-04 23:40:53

算法程序員前端

2022-09-24 09:03:55

前端單元測(cè)試冒泡排序

2021-11-10 09:17:18

程序員排序算法搜索算法

2023-02-09 07:39:01

2023-11-30 10:02:45

2019-10-29 15:22:24

Google算法搜索

2012-06-27 10:05:55

App Store搜索算法

2021-11-03 15:01:50

算法開源技術(shù)

2022-11-22 08:00:00

開源工具數(shù)據(jù)集

2009-06-15 09:15:25

谷歌研發(fā)團(tuán)隊(duì)必應(yīng)搜索
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)