树结构的遍历之BFS与DFS

645 阅读2分钟

来源

相信前端的小伙伴在做项目的时候肯定会遇到各种数据结构,接下来我们讲的就是一种Tree结构,在项目种还是比较实用的,例如:部门树、侧边栏的菜单树等,她可能是下面的这个样子

let treeData = [  {    name: 'a',    title: 'a',    children: [      {        name: 'a-1',        title: 'a-1',        children: null      },      {        name: 'a-2',        title: 'a-2',        children: [          {            name: 'a-2-1',            title: 'a-2-',            children: null          },          {            name: 'a-2-2',            title: 'a-2-2',            children: null          },        ]      },      {        name: 'a-3',        title: 'a-3',        children: null      },    ]  },  {    name: 'b',    title: 'b',    children: [      {        name: 'b-1',        title: 'b-1',        children: null      },      {        name: 'b-2',        title: 'b-2',        children: [          {            name: 'b-2-1',            title: 'b-2-1',            children: null          },          {            name: 'b-2-2',            title: 'b-2-2',            children: null          },        ]      },    ]  }]

前后端分离的时代既然有了数据了,那我们就要将它可视化的展示给我们的用户,以上面的代码结构为例,我们取值所有的name属性,实际应用中可能是个部门名称哦~,

遍历这种数据结构分为两种方式,他们分别是BFSDFS(这两种遍历方式不懂的可以自行查阅,看到结尾估计就能理解了,这里不多做介绍~)

DFS实现:

看到网上有很多的实现方式,咱们这里简化处理将代码量缩减,使代码更加简洁

一、递归遍历方式

function getNames (data) {  
    let arrayArguments = [...arguments][1]  
    let preArray = arrayArguments? arrayArguments : []  
    data.map(({name, children}) => {    
        name? preArray.push(name) : null
        children ? getNames(children, preArray): null  
    })  
    return preArray
}

这里使用argument这个为数组,来获取函数的参数,来避免显性的传入第二个参数,还有就是来避免外部变量的声明,将变量放在函数体内,防止全局污染,例如这种

getNames (data,list=[])

因为这里我们只用到两个参数,所以就直接用下标来取值[...arguments][1]

二、非递归遍历方式

function getNames (data) {  
    let names = []  
    let stackItem = {}  
    let stack = data.map(item => {    
        return item  
    })  
    while (stack.length) {    
        stackItem = stack.shift()    
        names.push(stackItem.name)     
        stack = stackItem.children? [...stackItem.children,...stack]: stack  }          return names
    }

非递归的方式我们将传入的数据(一般是引用类型),进行拷贝,重新开辟一份内存空间,防止污染传入的数据,因为数组的shift()方法会改变原有的数组结构,所以这里while循环体内数组的长度来判断什么时候结束循环,循环体内根据是否存在下级的children进行stack新数组的操作,两种方式的遍历结果如下:


BFS实现:

BFS的实现方式和DFS非递归方式雷同,在实现方式上我们只去改变一下这里就可以了

DFS非递归方式数组合并

stack = stackItem.children? [...stackItem.children,...stack]: stack  } 

BFS非递归方式数组合并

stack = stackItem.children? [...stack, ...stackItem.children]: stack  } 

只需要将合并数组的顺序颠倒 就可以产生不同的效果,打印结果如下:


相信根据打印结果大家就能理解到BFS与DFS的差别,这里没有想到BFS递归实现的好方法,如果你有好的方法,欢迎指导~