树形结构扁平化为数组示例代码

前言

树形结构存储数据是很方便的,里面有什么数据能够一目了然,但是在处理大量数据时,如果使用树形结构,增删改查所需要的时间复杂度会较高,让我们来看个例子

树形结构

以下是一个简单的树形结构数据

const tree = [
    { id:'01',value: 1, children: [
      { id:'01-1',value: 2, children: [
        { id:'01-1-1',value: 3},
        { id:'01-1-2',value: 4}
      ] },
      { id:'01-2',value: 5}
    ]},
    { id:'02',value: 6}
];

如果需要查找,最开始想到的算法就是递归

// 查找节点
const findValue=4  // 需要查找的节点值
const findNode=(tree)=>{
  for(let node of tree){
    if(node.value === findValue){  // 找到节点后返回
      return node
    }
    else if(node.children && findNode(node.children)){ // 如果有 children,就递归查找子树的节点
      return findNode(node.children)
    }
  }
}
const getNode=findNode(tree)
console.log(JSON.stringify(getNode));  // {"id":"01-1-2","value":4}

当 findValue 为根节点时为最好情况,时间复杂度是 O(1),如果 findValue 在树的最深叶子节点上,或者不存在,那么时间复杂度是 O(n),当树的深度较大时,查找所需要的时间将更多,维护树形结构的成本也更大

有什么其他方法可以降低这个复杂度呢,这就需要将树形结构扁平化

扁平化

先让我们来看扁平化后的数组

const flatArray=[
  {id:'01',value:1}, // 没有父节点 就将 parentId 设为 undefined 或不写
  {id:'01-1',value:2,parentId:'01'},
  {id:'01-1-1',value:3,parentId:'01-1'},
  {id:'01-1-2',value:4,parentId:'01-1'},
  {id:'01-2',value:5,parentId:'01'},
  {id:'02',value:6},
]

从上面扁平化后的数组可以看出,我们增加了一个属性 parentId,其值为父节点的 id,通过该属性与父节点保持连接,不会破坏原始的数据结构,这个时候要查找节点就方便多了

const findValue=4
const findNode=(arr)=>{
  for(let item of arr){  // 直接遍历就能找到
    if(item.value===findValue) return item
  }
}
const getNode=findNode(flatArray)
console.log(JSON.stringify(getNode)); // {"id":"01-1-2","value":4,"parentId":"01-1"}

怎么转化

怎么将树形结构转化为扁平化的数组,来看简单的示例

const flat=(tree,parentId,res=[])=>{  // 初始 res 为空数组
  for(let node of tree){
    res.push({
      id:node.id,
      parentId:parentId,
      value:node.value
    })
    if(node.children){  // 有子节点就递归遍历,传入的 parentId 参数为父节点 id, 也就是当前 node 的 id
      flat(node.children,node.id,res)
    }
  }
  return res
}
let flatArray=flat(tree,undefined)
for(let item of flatArray){
  console.log(JSON.stringify(item));  // 输出每个节点
}

输出的结果为:

在这里插入图片描述
这样就能转化成功了

也可以使用 reduce 方法,reduce 作为累加器,可以实现同样的效果

const flat = (tree, parentId) => {
  return tree.reduce((res,{id,value,children}) => { // 传入的参数为 上次积累值 res,和当前项解构
    res.push({id,parentId,value})
    if(children){
      res=[...res,...flat(children,id)]  // 利用扩展运算符 展开后合并
    }
    return res;
  }, [])  // 初始值为空数组
}
let flatArray=flat(tree,undefined)
for(let item of flatArray){
  console.log(JSON.stringify(item)); // 结果同上图
}

reduce 方法接收一个回调函数和累加器初始值,回调函数可以有4个参数:上一次调用回调返回的值、当前被处理的元素、当前元素在数组中的索引、调用 reduce 的数组,在这里我们用到的是前两个参数,传入上次回调返回的 res,以及当前元素解构出来的值

res 把当前元素存入后,如果当前元素有子节点时,遍历子节点,同时也要和 res 合并,最终的运算结果和上个方法一致

比较

与树形结构相比,扁平化后的数组:

  • 能够简化数据处理,因为线性结构通常更便于操作
  • 添加或删除数据时,也更加方便
  • 可以提高查询和搜索的性能
  • 20
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值