圖的深度優先遍歷類似於二叉樹

一、概述

圖是計算機科學中的一類非常重要的數據結構,用於描述物體間的關係。在圖中,節點(vertex)代表物體,邊(edge)則代表物體間的關係。通過遍歷圖,我們可以對圖中的節點進行訪問,同時也可以找出圖中節點之間的關係。

深度優先遍歷是圖遍歷中重要的一種方法,它類似於二叉樹的前序遍歷,按照深度優先的方式訪問圖中的節點。具體而言,深度優先遍歷會首先訪問某個節點,接着訪問該節點的鄰居節點,並進一步訪問鄰居的鄰居……直到訪問到所有相關的節點。

本文主要介紹如何實現圖的深度優先遍歷,以及為什麼它類似於二叉樹。

二、圖的深度優先遍歷

在實現圖的深度優先遍歷時,我們需要考慮如何遍歷每個節點,並標記哪些節點已經被遍歷過。

下面是一個示例圖,展示了深度優先遍歷中的遍歷順序:

     1 - 2 - 3
     |   |   |
     4 - 5 - 6

上圖中,我們從節點1開始遍歷,並首先訪問它的鄰居節點2。接着,我們訪問節點2的鄰居節點3,再訪問節點3的鄰居節點6……直到訪問了所有相關的節點。

下面給出實現圖的深度優先遍歷的代碼示例:

// 圖的鄰接表表示法
class Graph {
    constructor() {
        // 存儲圖的節點
        this.vertices = [];
        // 存儲圖的邊
        this.edges = new Map();
    }
    // 添加節點
    addVertex(v) {
        this.vertices.push(v);
        this.edges.set(v, []);
    }
    // 添加邊
    addEdge(v, w) {
        this.edges.get(v).push(w);
        this.edges.get(w).push(v);
    }
    // 深度優先遍歷
    dfs(startingNode) {
        const visited = new Set();
        this._dfs(startingNode, visited);
    }
    _dfs(vertex, visited) {
        visited.add(vertex);
        console.log(vertex);
        const neighbors = this.edges.get(vertex);
        for (let i = 0; i < neighbors.length; i++) {
            const neighbor = neighbors[i];
            if (!visited.has(neighbor)) {
                this._dfs(neighbor, visited);
            }
        }
    }
}

三、圖的深度優先遍歷類似於二叉樹的前序遍歷

雖然圖和二叉樹是兩種不同的數據結構,但它們之間的遍歷方式非常相似。圖的深度優先遍歷類似於二叉樹的前序遍歷,都是首先訪問本節點,接着訪問左子節點(或者鄰居節點),最後訪問右子節點(或者鄰居節點)。下面是一個對比圖和二叉樹前序遍歷的示意圖:

     圖的深度優先遍歷:           二叉樹的前序遍歷:
         1                           A
        / \                         / \
       2   4                       B   D
      / \   \                     / \   \
     3   5   6                   C   E   F
                                / \     / \
                               G   H   I   J

從上面的示意圖中可以看出,圖的深度優先遍歷和二叉樹的前序遍曆本質上是相同的遍歷方式。唯一的區別在於,圖沒有一個指定的根節點,而是從任一節點開始遍歷。

下面給出實現圖的深度優先遍歷類似於二叉樹前序遍歷的代碼示例:

class Graph {
    // ...
    // 深度優先遍歷類似於二叉樹前序遍歷
    dfs(node) {
        const visited = new Set();
        this._dfs(node, visited);
    }
    _dfs(node, visited) {
        visited.add(node);
        console.log(node);
        const neighbors = this.edges.get(node);
        for (const neighbor of neighbors) {
            if (!visited.has(neighbor)) {
                this._dfs(neighbor, visited);
            }
        }
    }
}

四、圖的深度優先遍歷與回溯

在實現圖的深度優先遍歷時,我們需要考慮如何在訪問之後回到原來的節點。相比於二叉樹的遍歷,圖的遍歷涉及到多個路徑,因此需要更加小心地考慮回溯的問題。

在深度優先遍歷過程中,我們使用遞歸函數來遍歷每個節點。如果我們走到一個死路,即當前節點沒有相鄰節點可訪問,那麼我們需要回到之前的節點(回溯),查找還有沒有相鄰節點可訪問。如果回到原來的節點後,還有未訪問的相鄰節點,那麼我們將繼續訪問,直到訪問完所有相關的節點。

下面給出實現遍歷時的回溯代碼示例:

class Graph {
    // ...
    // 深度優先遍歷
    dfs(startingNode) {
        const visited = new Set();
        this._dfs(startingNode, visited);
    }
    _dfs(node, visited) {
        visited.add(node);
        console.log(node);
        const neighbors = this.edges.get(node);
        for (const neighbor of neighbors) {
            if (!visited.has(neighbor)) {
                this._dfs(neighbor, visited);
            }
        }
    }
}

五、圖的深度優先遍歷與棧

在上面的示例代碼中,我們使用遞歸實現圖的深度優先遍歷。但遞歸調用可能會導致棧溢出的問題,特別是在遍歷大型圖時,很容易出現棧溢出錯誤。因此,我們可以使用棧(stack)來實現深度優先遍歷,而不是使用遞歸函數。

在使用棧實現深度優先遍歷時,我們需要考慮如何在遍歷完一個節點之後,回溯到它的前一個節點,並繼續遍歷。因此,我們需要維護一個棧,保存已經訪問過的節點。同時,我們還需要維護一個表,記錄每個節點是否已經被訪問過。

下面給出使用棧實現遍歷的代碼示例:

class Graph {
    // ...
  iter_dfs(startingNode) {
      const visited = new Set();
      const stack = [];
      stack.push(startingNode);
      while (stack.length !== 0) {
          const node = stack.pop();
          if (!visited.has(node)) {
              visited.add(node);
              console.log(node);
              const neighbors = this.edges.get(node);
              for (const neighbor of neighbors) {
                  if (!visited.has(neighbor)) {
                      stack.push(neighbor);
                  }
              }
          }
      }
  }
}

六、總結

對於圖的深度優先遍歷類似於二叉樹的前序遍歷,我們需要遍歷每個節點,並標記哪些節點已經被遍歷過。在實現遍歷時,我們需要考慮如何回溯到原來的節點,以及使用棧來替代遞歸實現深度優先遍歷。

圖的深度優先遍歷類似於二叉樹的前序遍歷,但需要注意的是,圖的遍歷涉及到多個路徑,因此需要更加小心地考慮回溯的問題。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/246023.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-12 13:12
下一篇 2024-12-12 13:12

相關推薦

  • Python遍歷集合中的元素

    本文將從多個方面詳細闡述Python遍歷集合中的元素方法。 一、for循環遍歷集合 Python中,使用for循環可以遍歷集合中的每個元素,代碼如下: my_set = {1, 2…

    編程 2025-04-29
  • Python如何遍歷字典中的key和value

    本文將詳細講解Python中如何遍歷字典中的key和value,包括多種遍歷方式以及在遍歷過程中的一些應用場景。 一、遍歷字典中的key和value 在Python中,字典是一種無…

    編程 2025-04-29
  • 深度查詢宴會的文化起源

    深度查詢宴會,是指通過對一種文化或主題的深度挖掘和探究,為參與者提供一次全方位的、深度體驗式的文化品嘗和交流活動。本文將從多個方面探討深度查詢宴會的文化起源。 一、宴會文化的起源 …

    編程 2025-04-29
  • 使用PHP foreach遍歷有相同屬性的值

    本篇文章將介紹如何使用PHP foreach遍歷具有相同屬性的值,並給出相應的代碼示例。 一、基礎概念 在講解如何使用PHP foreach遍歷有相同屬性的值之前,我們需要先了解幾…

    編程 2025-04-28
  • Python下載深度解析

    Python作為一種強大的編程語言,在各種應用場景中都得到了廣泛的應用。Python的安裝和下載是使用Python的第一步,對這個過程的深入了解和掌握能夠為使用Python提供更加…

    編程 2025-04-28
  • 二叉樹非遞歸先序遍歷c語言

    本文將為您詳細介紹二叉樹的非遞歸先序遍歷算法,同時提供完整的C語言代碼示例。通過本文,您將了解到二叉樹的先序遍歷算法,以及非遞歸實現的方式。 一、二叉樹的先序遍歷算法介紹 在介紹二…

    編程 2025-04-28
  • Python如何遍歷列表

    在Python編程中,列表是一種常用的數據類型,它允許我們存儲多個值。但是,我們如何遍歷列表並對其中的每個值進行操作呢? 一、for循環遍歷列表 fruits = [‘apple’…

    編程 2025-04-28
  • Python遍歷字典刪除元素

    本文主要介紹Python中如何遍歷字典並刪除元素。在實際應用中,遍歷字典並刪除元素是一種非常常見的操作,但需要注意的是,直接在字典中刪除元素可能會改變字典中其他元素的索引順序,因此…

    編程 2025-04-28
  • Python列表構建二叉樹

    本文將從以下幾個方面詳細闡述如何使用Python列表構建二叉樹: 一、二叉樹的基本概念 二叉樹是一種重要的數據結構,其每個節點最多有兩個子節點,左子節點和右子節點。左子節點始終比右…

    編程 2025-04-27
  • Python遞歸深度用法介紹

    Python中的遞歸函數是一個函數調用自身的過程。在進行遞歸調用時,程序需要為每個函數調用開闢一定的內存空間,這就是遞歸深度的概念。本文將從多個方面對Python遞歸深度進行詳細闡…

    編程 2025-04-27

發表回復

登錄後才能評論