You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于哈希表实现扁平对象数组到多层级树形结构的优化问题

基于哈希表实现扁平对象数组到多层级树形结构的优化问题

嘿,我来帮你梳理下这个问题!首先得纠正一个小误解:你最开始找到的那个哈希表方案其实是支持多层嵌套的,它之所以看起来好像只能处理单层级,可能是你测试的时候没注意到——因为它的逻辑是通过哈希表快速查找父节点,不管嵌套多少层都能正确挂载子节点。

接下来咱们逐个解决你遇到的两个问题:


问题1:移除无子类节点的空children数组

你的第一个需求是不想让没有子节点的对象带上children: []这个空属性。咱们可以在构建完整个树形结构之后,遍历每个节点删掉空的children;不过更高效的方式是只在需要的时候才添加children属性,避免预先创建空数组。修改后的代码如下:

const createDataTree = dataset => {
    const hashTable = Object.create(null);
    const dataTree = [];

    // 第一步:先把所有节点存入哈希表,不预设children属性
    dataset.forEach(aData => {
        hashTable[aData.id] = { ...aData };
    });

    // 第二步:遍历节点,挂载子节点到对应的父节点上
    dataset.forEach(aData => {
        if (aData.parent_id) {
            // 如果父节点还没有children属性,先创建空数组
            if (!hashTable[aData.parent_id].children) {
                hashTable[aData.parent_id].children = [];
            }
            // 将当前节点挂载到父节点的children中
            hashTable[aData.parent_id].children.push(hashTable[aData.id]);
        } else {
            // 没有parent_id的根节点直接加入树形数组
            dataTree.push(hashTable[aData.id]);
        }
    });

    return dataTree;
};

// 测试示例数据
const data = [
   {"id":"m1", "name":"M1"},
   {"id":"m2", "name":"M2"},
   {"parent_id":"m2", "id":"s1", "name":"S1"},
   {"parent_id":"m2", "id":"s2", "name":"S2"},
   {"parent_id":"m2", "id":"s3", "name":"S3"},
   {"parent_id":"s3", "id":"b1", "name":"B1"}
];

console.log(createDataTree(data));

这样处理后,只有真正拥有子节点的对象才会带有children属性,完全符合你的需求。


问题2:关于哈希表和dataTree的“自动更新”疑惑

你提到的“hashTable修改后dataTree自动更新”其实是JavaScript引用类型的特性,不是什么魔法:

当我们执行hashTable[aData.id] = { ...aData }时,我们创建了一个新对象,并把这个对象的引用存在哈希表里。之后把hashTable[aData.id]推入dataTree时,其实是把这个对象的引用放进了数组,而非复制新对象。所以后续修改哈希表里的对象(比如添加children并挂载子节点),本质上是在修改同一个对象的内容,dataTree里的引用指向的也是这个对象,自然会同步看到更新后的结果。


关于性能的补充

这个哈希表方案的时间复杂度是O(n),只需要遍历数组两次,不管数组规模多大(哪怕几千条)、嵌套层级有多深(几十层),效率都非常高,几乎是最优实现了,不需要再找更快的方案。

如果需要处理边界情况(比如存在无效的parent_id,指向不存在的节点),可以在挂载子节点时加个判断:

if (aData.parent_id && hashTable[aData.parent_id]) {
    // 仅当父节点存在时才挂载
    if (!hashTable[aData.parent_id].children) {
        hashTable[aData.parent_id].children = [];
    }
    hashTable[aData.parent_id].children.push(hashTable[aData.id]);
}

这样可以避免无效父ID导致的报错。

备注:内容来源于stack exchange,提问作者DHHJ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 09:53:14