javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > js递归树形结构

JavaScript递归构建树形结构的两种方法

作者:郭泽元

本文给大家详细讲解如何使用纯JavaScript递归方法将扁平数据转换为树形结构,并解释两种实现方式的原理和区别,感兴趣的朋友一起看看吧

我将详细讲解如何使用纯 JavaScript 递归方法将扁平数据转换为树形结构,并解释两种实现方式的原理和区别。

原始数据结构

let data = [
    {name: '一级', id: 12, pid: 0},    // pid=0 表示根节点
    {name: '二级', id: 32, pid: 0},    // pid=0 表示根节点
    {name: '一级-1', id: 23, pid: 12}, // pid=12 表示父节点是id=12的节点
    {name: '二级-1', id: 34, pid: 32}, // pid=32 表示父节点是id=32的节点
];

方法一:递归实现详解

代码实现

function buildTree(items, parentId = 0) {
    let result = [];
    // 1. 找出所有父节点为parentId的项
    let children = items.filter(item => item.pid === parentId);
    // 2. 递归处理每个子项
    children.forEach(child => {
        // 3. 查找当前项的子项
        let childNodes = buildTree(items, child.id);
        // 4. 如果有子项,则添加到children属性中
        if (childNodes.length > 0) {
            child.children = childNodes;
        }
        result.push(child);
    });
    return result;
}
let treeData = buildTree(data);

执行过程解析

时间复杂度分析

方法二:优化实现详解(非递归)

代码实现

function buildTreeOptimized(items) {
    let map = {};  // 存储id到节点的映射
    let result = [];  // 最终结果
    // 1. 构建映射表
    items.forEach(item => {
        map[item.id] = {...item, children: []};
    });
    // 2. 构建树形结构
    items.forEach(item => {
        let node = map[item.id];
        if (item.pid === 0) {
            // 根节点
            result.push(node);
        } else {
            // 子节点
            if (map[item.pid]) {
                map[item.pid].children.push(node);
            }
        }
    });
    return result;
}
let optimizedTree = buildTreeOptimized(data);

执行过程解析

{
    12: {name: '一级', id:12, pid:0, children: []},
    32: {name: '二级', id:32, pid:0, children: []},
    23: {name: '一级-1', id:23, pid:12, children: []},
    34: {name: '二级-1', id:34, pid:32, children: []}
}

时间复杂度分析

两种方法对比

特性递归方法优化方法
实现方式递归循环+对象引用
时间复杂度O(n²)O(n)
空间复杂度O(n) (调用栈)O(n) (映射表)
适用场景小型数据集大型数据集
代码可读性较高中等
最大递归深度限制可能受限无限制

实际应用建议

扩展功能

可以在基础实现上添加以下功能:

// 添加排序功能
function buildTree(items, parentId = 0, sortKey = 'id') {
    let result = [];
    let children = items.filter(item => item.pid === parentId);
    // 排序
    children.sort((a, b) => a[sortKey] - b[sortKey]);
    children.forEach(child => {
        let childNodes = buildTree(items, child.id, sortKey);
        if (childNodes.length > 0) {
            child.children = childNodes;
        }
        result.push(child);
    });
    return result;
}
// 添加节点过滤
function buildTreeWithFilter(items, parentId = 0, filterFn = () => true) {
    let result = [];
    let children = items.filter(item => item.pid === parentId && filterFn(item));
    children.forEach(child => {
        let childNodes = buildTreeWithFilter(items, child.id, filterFn);
        if (childNodes.length > 0) {
            child.children = childNodes;
        }
        result.push(child);
    });
    return result;
}

理解这些实现原理后,你可以根据具体业务需求灵活调整树形结构的构建方式。

到此这篇关于JavaScript 递归构建树形结构详解的文章就介绍到这了,更多相关js递归树形结构内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文