深度优先遍历&广度优先遍历

一、定义

深度优先遍历(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阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容