zoukankan      html  css  js  c++  java
  • JavaScript通过reduce+递归实现树的深度遍历

    越是结构化的有规律的数据操作起来越简单,只是我们没有找到规律和工具。

    首先贴代码

    首先定义了一个树结构,需求是通过任意节点遍历出其所有的子节点。
    根据需求的不同,就会有深度遍历和广度遍历两种,getAllChildrenDFSByReduce(),getAllChildrenDFSByStack()是深度遍历的两种实现,getAllChildrenBFSByQueue()是广度遍历的实现。

    class Node {
      constructor(id, data, parent) {
        this.id = id
        this.data = data
        this.parent = parent || null
        this.children = []
    
        if (this.parent !== null) {
          this.parent.children.push(this)
        }
      }
    
      // DFS使用递归作为驱动力
      // 使用递归只能实现前序和后序遍历,取决于item放在什么位置
      getAllChildrenDFSByReduce() {
        return this.children.reduce((res, item) => {
           return [...res, item, ...item.getAllChildrenDFSByReduce()]
        }, [])
      }
    
      // DFS使用栈遍历作为驱动力
      // 对比递归的方式我们发现: 1. 使用递归(调用栈)代替了stack 2. 使用reduce代替了data
      getAllChildrenDFSByStack() {
        const stack = [this]
        const data = []
        while (stack.length !== 0) {
          // 以前序遍历为例
          const node = stack.pop()
          if (node !== this) data.push(node)
          stack.push(...node.children.reverse())
        }
        return data
      }
    
      // BFS使用队列遍历作为驱动力
      getAllChildrenBFSByQueue() {
        const queue = [this]
        const data = []
        while (queue.length !== 0) {
          const node = queue.shift()
          data.push(...node.children)
          queue.push(...node.children)
        }
        return data
      }
    }
    
    let id = 1
    const root = new Node(id++, {}, null)
    new Node(id++, {}, root)
    new Node(id++, {}, root)
    new Node(id++, {}, root.children[0])
    new Node(id++, {}, root.children[0])
    new Node(id++, {}, root.children[1])
    new Node(id++, {}, root.children[1])
    new Node(id++, {}, root.children[0].children[0])
    new Node(id++, {}, root.children[0].children[0])
    new Node(id++, {}, root.children[0].children[1])
    new Node(id++, {}, root.children[0].children[1])
    new Node(id++, {}, root.children[1].children[0])
    new Node(id++, {}, root.children[1].children[0])
    new Node(id++, {}, root.children[1].children[1])
    new Node(id++, {}, root.children[1].children[1])
    
    /*
                     1
               2            3
            4     5      6    7
           8  9 10 11 12 13 14 15
    */
    
    
    // [2, 4, 8, 9, 5, 10, 11, 3, 6, 12, 13, 7, 14, 15]
    console.log(root.getAllChildrenDFSByReduce().map(item => item.id))
    // [2, 4, 8, 9, 5, 10, 11, 3, 6, 12, 13, 7, 14, 15]
    console.log(root.getAllChildrenDFSByStack().map(item => item.id))
    // [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
    console.log(root.getAllChildrenBFSByQueue().map(item => item.id))
    

    深度优先遍历和广度优先遍历

    深度优先遍历(DFS)和广度优先遍历(BFS)是树和图搜索的两种策略,一种是纵深优先(子节点优先),一种是广度优先(父节点优先)

    做最短路径搜索时,DFS耗性能,BFS耗内存

    深度遍历依赖栈结构,通过不断的回溯(很像递归)将子节点优先摘取出来,二叉树里面根据根节点和左右子树节点的排列顺序分为前序(根左右),中序(左根右),后序(左右根)
    广度遍历又叫层序遍历,依赖队列结构,通过队列将录入的节点依次摘出,不存在回溯过程。

    递归的思想

    递归的思想除了分治之外,关键在于学会抽象和隔离问题的复杂性。
    比如:全世界的人口 = 我 + 我旁边的同事 + 我的家人 + 我的朋友 + ...,这就陷入了复杂问题的细节之中;
    如果不考虑细节:全世界的人口 = 一个人 + 剩下来的人,就轻松很多;
    如果恰好发现”剩下来的人 = 一个人 + 再次剩下来的人“,那就可以用递归了,因为问题是相似的。

    递归,分治与第一性原理

    第一性原理是告诉我们分析问题:首先直击本质,再具体解决各个子问题。
    火星旅行票价降低100倍 = 飞船成本降低10倍 + 飞船载客量提高10倍,然后再考虑如果降低飞船成本,如何提高载客量,这是马斯克的逻辑。
    这三个词的本质是一样的,告诉我们分析问题的策略:先宏观再微观,先抽象再具体。

  • 相关阅读:
    通过C#代码调用Dynamics 365 Web API执行批量操作
    Dynamics 365 CE Update消息PostOperation阶段Image的尝试
    sql注入100种姿势过waf(二):过安全狗
    sql注入100种姿势过waf(一):waf 了解
    双文件上传突破利用
    渗透实例(一):点后缀突破上传文件
    IIS6.0使用冒号上传漏洞利用
    利用3389端口监视管理员登录
    Windows突破远程连接最大数去掉限制登录
    MIME格式解析
  • 原文地址:https://www.cnblogs.com/Peter2014/p/13187008.html
Copyright © 2011-2022 走看看