最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JavaScript 算法之树的深度优先与广度优先

    正文概述 掘金(Lion)   2021-02-11   501

    前言

    在前端的工作中,如果遇到树形 DOM 结构、树型控件、级联选择等等需求,都需要使用到深度优先遍历(简称 DFS)和广度优先遍历(简称 BFS)。 DFS 和 BFS 可能也是前端处理复杂需求用到最多的算法之一了。今天就让我们来好好学习它。

    上面描述的“树型控件”、“级联选择”,它们处理的数据结构都是树,那么树又是什么呢?

    树是一种分层数据的抽象模型,树可以看做是一种特殊的链表,只是链表只有一个 next 指向下一个节点,而树的每个节点都有多个 next 指向下一个节点。

    一个树结构包含一系列存在父子关系的节点。每个节点都有一个父节点(除了顶部的第一个节点)以及零个或多个子节点:

    JavaScript 算法之树的深度优先与广度优先

    JavaScript 表示树

    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:[]
            }
          ]
        }
      ]
    }
    

    看到这个结构是不是非常熟悉,工作中应该算是经常碰到了把。对于树的常见操作有: DFS 、 BFS 以及二叉树(一种特殊的树)的先中后序遍历。今天本文的重点则是 DFS 以及 BFS 。

    DFS

    深度优先遍历,尽可能深的搜索树的分支。

    JavaScript 算法之树的深度优先与广度优先
    序号表示被搜索的顺序,它的算法口诀是:

    1. 访问根节点;
    2. 对根节点的 children 挨个(递归)进行深度优先遍历。


    代码实现:

    # tree 为上文所述的结构,这里就不重复展示
    
    # 深度优先代码
    const dfs = (node)=>{
      console.log(node.value);
      node.children.forEach(dfs);
    }
    
    # 调用
    dfs(tree);
    

    打印结果输出顺序: a、b、d、e、c、f、g 。

    BFS

    广度优先遍历,先访问离根节点最近的节点。
    JavaScript 算法之树的深度优先与广度优先
    序号表示被搜索的顺序,先把同层的节点给遍历完,再去遍历子节点。它的算法口诀是:

    1. 新建一个队列,把根节点入队;
    2. 把对头出队并访问;
    3. 把对头的 children 挨个入队;
    4. 重复(循环)第二、三步,直到队列为空。


    代码实现:

    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 。

    渲染 Antd 中树组件

    在实际工作中我们肯定碰到过需要去渲染一棵树的情景,我们就以渲染 Antd 中树组件为例来巩固下所学知识。

    import { Tree } from 'antd';
    
    const { TreeNode } = Tree;
    
    class Demo extends React.Component {
    
      render() {
        return (
          <Tree>
            <TreeNode  key="0-0">
              <TreeNode  key="0-0-0" >
                <TreeNode  key="0-0-0-0" />
                <TreeNode  key="0-0-0-1" />
              </TreeNode>
              <TreeNode  key="0-0-1">
                <TreeNode  key="0-0-1-0" />
              </TreeNode>
            </TreeNode>
          </Tree>
        );
      }
    }
    
    ReactDOM.render(<Demo />, mountNode);
    

    渲染效果:
    JavaScript 算法之树的深度优先与广度优先

    其中 TreeNode 是已经写好的,假设现在我们要根据后台返回的数据结构来渲染成相应的树,该怎么做呢?

    后台返回的数据结构可能会长这个样子:

    const tree = [
      {
        key: "0",
        title: "0",
        children: [
          {
            key: "0-1",
            title: "0-1",
            children: []
          },
          {
            key: "0-2",
            title: "0-2",
            children: []
          }
        ]
      },
      {
        key: "1",
        title: "1",
        children: [
          {
            key: "1-1",
            title: "1-1",
            children: []
          },
          {
            key: "1-2",
            title: "1-2",
            children: []
          }
        ]
      }
    ];
    

    代码实现:

    import React from "react";
    import ReactDOM from "react-dom";
    import "antd/dist/antd.css";
    import "./index.css";
    import { Tree } from "antd";
    
    const { TreeNode } = Tree;
    
    class Demo extends React.Component {
      dfs = (node) => {
        return (
          <TreeNode title={node.title} key={node.key}>
            {node.children.map(this.dfs)}
          </TreeNode>
        );
      };
    
      render() {
        return <Tree>{tree.map(this.dfs)}</Tree>;
      }
    }
    
    ReactDOM.render(<Demo />, document.getElementById("container"));
    

    最终渲染效果:
    JavaScript 算法之树的深度优先与广度优先

    小结

    深度优先和广度优先并没有想象中的那么复杂,而且在平时项目中的应用非常广泛,因此需要我们重点掌握。


    起源地下载网 » JavaScript 算法之树的深度优先与广度优先

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元