深度優先遍歷&廣度優先遍歷

一、定義

深度優先遍歷(Depth-First Search,DFS)和廣度優先遍歷(Breadth-First Search,BFS)是兩種主要的圖或樹結構的遍歷算法。
DFS優先深入地探索一個節點的子節點,直到該節點的所有子節點都已被探索完,然后再回溯到該節點的同級節點進行探索;
BFS則優先探索一個節點的所有同級節點,再逐級向下探索。
在前端的工作中,如果遇到樹形 DOM 結構、樹型控件、級聯選擇等等需求,都需要使用到DFS和BFS。

二、算法步驟

2.1 樹

樹是一種分層數據的抽象模型,樹可以看做是一種特殊的鏈表,只是鏈表只有一個 next 指向下一個節點,而樹的每個節點都有多個 next 指向下一個節點。

一個樹結構包含一系列存在父子關系的節點。每個節點都有一個父節點(除了頂部的第一個節點)以及零個或多個子節點:


image.png

JavaScript 中沒有樹這種數據結構,但是可以用 Object 和 Array 來模擬一顆樹。

const tree = {
  value:"a",
  children:[
    {
      value:"b",
      children:[
        {
          value:"d",
          children:[
            {
              value:"e",
              children:[]
            }
          ]
        }
      ]
    },
    {
      value:"c",
      children:[
        {
          value:"f",
          children:[]
        },
        {
          value:"g",
          children:[]
        }
      ]
    }
  ]
}

var data = [
      {
        name: "a",
        children: [
          {
            name: "b",
            children: [
              {
                name: "e",
              },
            ],
          },
          {
            name: "c",
            children: [
              {
                name: "f",
              },
            ],
          },
          {
            name: "d",
            children: [
              {
                name: "g",
              },
            ],
          },
        ],
      },
      {
        name: "a2",
        children: [
          {
            name: "b2",
            children: [
              {
                name: "e2",
              },
            ],
          },
          {
            name: "c2",
            children: [
              {
                name: "f2",
              },
            ],
          },
          {
            name: "d2",
            children: [
              {
                name: "g2",
              },
            ],
          },
        ],
      },
    ];

2.2 深度優先遍歷(DFS)

深度優先遍歷,盡可能深的搜索樹的分支。


image.png

image.png

序號表示被搜索的順序,它的算法口訣是:
訪問根節點;
對根節點的 children 挨個(遞歸)進行深度優先遍歷。

# tree 為上述的結構

# 深度優先代碼
const dfs = (node)=>{
  console.log(node.value);
  node.children.forEach(dfs);
}

# 調用
dfs(tree);

打印結果輸出順序: a、b、d、e、c、f、g 。

2.3 廣度優先遍歷(BFS)

廣度優先遍歷,先訪問離根節點最近的節點。


image.png
序號表示被搜索的順序,先把同層的節點給遍歷完,再去遍歷子節點。它的算法口訣是:
新建一個隊列,把根節點入隊;
把對頭出隊并訪問;
把對頭的 children 挨個入隊;
重復(循環)第二、三步,直到隊列為空。
const bfs = (root)=>{
  # 根節點入隊
  const stack = [root];
  # 只要棧不為空就一直循環
  while (stack.length > 0){
    # 取出棧首
    const node = stack.shift();
    # 遍歷根節點,把它的子節點推入棧尾
    node.children.forEach((item)=> stack.push(item));
    # 打印節點值
    console.log(node.value);
  }
}

bfs(tree);


打印結果輸出順序: a、b、c、d、e、f、g 。

三、使用場景 & 應用案例

3.1 深度優先遍歷

● 在圖或樹的復雜結構中搜索特定節點。
● 用于解決如迷宮搜索、尋找連通性組件等問題。
● 查找文件路徑
● 二叉樹的遍歷

3.2 廣度優先遍歷

● 尋找最短路徑,如無權重圖的最近節點或社交網絡中的度數。
● 逐層遍歷,如層級結構的打印。
● 權限系統
● Web 爬蟲(廣度優先搜索也被應用在互聯網搜索引擎的網頁爬蟲技術中,以盡可能廣泛地爬取頁面。)

四、優點和缺點

4.1深度優先遍歷 (DFS):

優點:

  1. 路徑檢測:DFS 非常適合搜索所有可能的路徑,因為它走的“更深”。
  2. 內存較少:相比 BFS,DFS 使用的內存較少。因為它只需要存儲單條路徑上的節點。

缺點:

  1. 時間較多:在某些情況下,尤其是在目標節點離初始節點較近時,或者在解決最短路徑問題時, DFS 可能需要花費不必要的更多時間。
  2. 無限循環:在非樹形圖結構中,由于 DFS 偏向深入,可能遇到不斷深入但找不到解的歷史循環問 題。
    深度優先遍歷的優點在于能快速找到解決方案,且易于實現,但有可能陷入死循環或者掉入一些非最優的情況。

4.2廣度優先遍歷 (BFS):

優點:

  1. 最短路徑:在樹形或圖形結構中,BFS 可以找到從根節點到目標節點的最短路徑。
  2. 層級遍歷:由于 BFS 是逐層遍歷,因此很適用于需要按層級遍歷的場合。

缺點:

  1. 內存:相比 DFS,BFS 使用的內存較多。尤其是在樹的分支很多時,因為它需要存儲整個擴展的節 點隊列。
  2. 路徑檢測:在需要找到所有可能的路徑時,BFS效率較低。
    廣度優先遍歷可以找到最優解,特別是在需要找到最短路徑的問題中,但可能需要更多的存儲空間。

五、時間和空間復雜度

5.1 BFS(廣度優先搜索)

  1. 時間復雜度:是O(V+E),其中V是圖中頂點(Vertex)的數量,E是圖中邊(Edge)的數量。這是因為在算法執行過程中,每個頂點和每條邊都會被探查一次。
  2. 空間復雜度:是O(V),其中V是圖中的頂點的數量。在最壞的情況下,即在隊列中存放了圖的所有頂點,所以空間復雜度與頂點的數量有關。

5.2 DFS(深度優先搜索)

  1. 時間復雜度:是O(V+E),其中V是圖中頂點(Vertex)的數量,E是圖中邊(Edge)的數量。與BFS一樣,這是因為在算法執行過程中,每個頂點和每條邊都會被訪問一次。
  2. 空間復雜度:是O(V),其中V是圖中的頂點的數量。在最壞的情況下,即在調用棧中存放了圖的所有頂點,所以空間復雜度與頂點的數量有關。
    注意:以上的復雜度分析都是基于鄰接列表的圖數據結構進行的。如果使用鄰接矩陣,由于需要遍歷每個點對應的所有邊,因此BFS和DFS的時間復雜度會變為O(V^2)。
    所以,當選擇圖的數據結構時(例如,鄰接矩陣還是鄰接列表),需要考慮到實際應用的特點,如圖的稀疏或密集程度,以選擇最優的數據結構,從而提高程序的效率。

六、 總結

深度優先遍歷和廣度優先遍歷是兩種基本且重要的圖與樹的遍歷算法,選擇使用哪一種遍歷方法取決于問題的具體需求,理解它們的運作原理及適用場景是所有算法學習基礎。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,570評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,786評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,219評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,438評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,971評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,796評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,995評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,230評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,697評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容