总结四种扁平数组转树形结构方法,时间和空间复杂度依次降低
1w条数据耗时对比
1w条数据时,arrToTree4 耗时1毫秒内,可忽略
10w条数据耗时对比
10w条数据时,arrToTree 已无法正常工作
1、递归
递归是常见方法,只是随数据量提升开销较大。空间复杂度O(k) 时间复杂度O(n^k)
同样是递归,arrToTree 的效率比 arrToTree1 慢数十倍
function arrToTree(arr, parentId) {
const tree = []
arr = JSON.parse(JSON.stringify(arr)) //避免污染原数据
arr.forEach(item => {
if (item.pid === parentId) {
item.children = arrToTree(arr, item.id)
tree.push(item)
}
})
return tree
}
function arrToTree1(arr, parentId) {
return arr.filter(item => item.pid === parentId).map(item =>
({ ...item, children: arrToTree1(arr, item.id) }))
}
2、循环
利用引用数据类型特点做到数据关联。空间复杂度O(1) 时间复杂度O(n^2)
function arrToTree2(arr, parentId) {
const tree = []
arr = JSON.parse(JSON.stringify(arr))//避免污染原数据
arr.forEach(item => {
item.children = arr.filter(child => child.pid === item.id)
if (item.pid === parentId) {
tree.push(item)
}
})
return tree
}
3、索引
利用对象创建id索引,提高查找效率。
利用引用数据类型特点做到数据关联。
空间复杂度O(1) 时间复杂度O(n)
function arrToTree3(arr) {
const map = {}
const tree = []
arr.forEach(item => {//将数组元素id为key,元素为value,添加到对象中
map[item.id] = { ...item, children: [] }
})
for (const id in map) {
const item = map[id]
const pItem = map[item.pid]
if (pItem) {//找到父节点,将自己添加到父节点children中
pItem.children.push(item)
} else {//找不到父节点说明当前item是根节点
tree.push(item)
}
}
return tree
}
4、索引-(推荐)
只循环一次,效率最高。
利用对象创建id索引,提高查找效率。利用引用数据类型特点做到数据关联。
空间复杂度O(1) 时间复杂度O(n)
function arrToTree4(arr, parentId) {
const map = {}
const tree = []
arr.forEach(item => {
const id = item.id
const pid = item.pid
if (!map[id]) {
map[id] = { ...item, children: [] }
} else {
map[id] = { ...item, ...map[id] }// (1)
}
if (map[pid]) {
map[pid].children.push(map[id])
} else {//没有父节点就先创建索引,等循环到父节点时再做数据合并 ->(1)
map[pid] = { children: [map[id]] }
}
if (pid === parentId) {
tree.push(map[id])
}
})
return tree
}
构造数据
function getData(){
let id = 1
return Array.from({ length: 100000 }, item => ({ pid: Math.floor(id / 3), id: id++ }))
}
// (3^n)<=100000,最大层数=n+1
测试数据
data = [
{
id: 1,
pid: 0,
label: '第一层1',
value: '1.1'
},
{
id: 2,
pid: 0,
label: '第一层2',
value: '1.2'
},
{
id: 3,
pid: 1,
label: '第二层1',
value: '2.1'
},
{
id: 5,
pid: 4,
label: '第三层1',
value: '3.1'
},
{
id: 6,
pid: 4,
label: '第三层2',
value: '3.2'
},
{
id: 4,
pid: 1,
label: '第二层2',
value: '2.2'
}
]