算法:一维数组转成树形结构菜单

这篇博客探讨了一维数组转换为树形结构的问题,通过广度优先搜索(BFS)和深度优先搜索(DFS)算法进行解析。文章提供了这两种算法的JavaScript实现,并分析了它们的时间复杂度和空间复杂度。同时,附带了不同层级菜单数据的转换示例,展示了算法的实际应用。
摘要由CSDN通过智能技术生成

题目:
数据库表中存着所有菜单,使用select * from menu,查找出的是一维数组列表,请把它生成一个菜单树形结构的json。

举例
原始数据

[
    { "id": 20, "parentId": 0, "name": "一级菜单1" },
    { "id": 21, "parentId": 0, "name": "一级菜单2"  },
    { "id": 22, "parentId": 0, "name": "一级菜单3"  },
    { "id": 23, "parentId": 0, "name": "一级菜单4"  },
    { "id": 24, "parentId": 20, "name": "二级菜单"  },
    { "id": 25, "parentId": 20, "name": "二级菜单"  },
    { "id": 26, "parentId": 24, "name": "三级菜单"  },
    { "id": 27, "parentId": 24, "name": "三级菜单"  },
    { "id": 28, "parentId": 21, "name": "二级菜单"  },
    { "id": 29, "parentId": 21, "name": "二级菜单"  },
    { "id": 30, "parentId": 29, "name": "三级菜单"  },
    { "id": 31, "parentId": 30, "name": "四级菜单"  },
    { "id": 32, "parentId": 31, "name": "五级菜单"  }
]

预期输出结果(同级菜单在当前层级上的位置可以不同):

[
    { "id": 22, "parentId": 0, "name": "一级菜单3" },
    { "id": 23, "parentId": 0, "name": "一级菜单4" },
    { "id": 20, "parentId": 0, "name": "一级菜单1",
        "children": [
            { "id": 25, "parentId": 20, "name": "二级菜单" },
            { "id": 24, "parentId": 20, "name": "二级菜单",
                "children": [
                    { "id": 26, "parentId": 24, "name": "三级菜单" },
                    { "id": 27, "parentId": 24, "name": "三级菜单" }
                ]
            }
        ]
    },
    {
        "id": 21, "parentId": 0, "name": "一级菜单2",
        "children": [
            { "id": 28, "parentId": 21, "name": "二级菜单" },
            { "id": 29, "parentId": 21, "name": "二级菜单",
                "children": [
                    { "id": 30, "parentId": 29, "name": "三级菜单",
                        "children": [
                            { "id": 31, "parentId": 30, "name": "四级菜单",
                                "children": [
                                    { "id": 32, "parentId": 31, "name": "五级菜单" }
                                ]
                            }
                        ]
                    }
                ]
            }
        ]
    }
]

分析
这是典型的一维数组转树形结构的问题。我们可以想上面的N叉树想象成二叉树,可以转化为二叉树的遍历问题。

第一时间能想到两种算法,广度优先搜索算法(BSF)深度优先搜索算法(DSF)

广度优先搜索算法(BSF)

也可以认为是层级遍历算法,从树的跟节点开始一层层往下遍历,因此层级的特点比较突出。

/**
 * 广度优先搜索
 * @param list json数据
 */
const bfs = (list: any[]): any[] => {
    const heads: any[] = [{ id: 0, children: [] }];// 创建一个头指针,heads[0].children就是最终结果
    const levels: any[][] = [heads];// 按层存储,每层都是一个数组
    let lv = 0;// 层级
    let count = 0;// 统计复杂度
    while (list.length > 0) {
        const level = levels[lv];
        // 遍历第j层,找该层第j个元素的children
        for (let j = 0; j < level.length; j++) {
            let i = 0;
            // 遍历原数据
            while (i < list.length) {
                count ++;
                if (list[i].parentId === level[j].id) {
                    if (!level[j].children) { level[j].children = []; }
                    level[j].children.push(list[i]);// 挂到父级节点下
                    if (!levels[lv + 1]) { levels.push([]); }
                    levels[lv + 1].push(list[i]);// 孩子属于下一层
                    list.splice(i, 1);// 移除
                } else {
                    i++; // 指针继续
                }
            }
        }
        lv++; // 层级
    }
    console.log('bfs=',count)
    console.log('lv=',lv)
    return levels[0][0].children;
}

深度优先搜索算法(DSF)

是从跟节点开始,一直遍历到叶子节点结束。

/**
 * 深度优先搜索
 * @param list json数据
 */
const dfs = (list: any[]): any[] => {
    let count = 0;// 统计复杂度
    /**
     * 递归方法
     * @param p     父级菜单
     * @param id    父级id
     */
    const loop = (p: any,id = 0) => {
        let i = 0;
        while(i < list.length) {
            count ++;
            const item = list[i];
            if (item.parentId === id) {
                if (!p.children) p.children = [];
                p.children.push(item)
                loop(item, item.id);
                list.splice(i,1);// 移除
            } else {
                i ++;
            }
        }
    }
    const header = {id: 0, children: []};// 创建头指针,header.children是结果
    loop(header, header.id);

    console.log(JSON.stringify(header.children))
    console.log('dfs=',count)
    return header.children
}

复杂度分析

时间复杂度计算原则按照最大复杂度计算。参考上面的例子,菜单层级为lv层,原始数据长度为n,
BFS:
时间复杂度:o = (n/lv) ^ lv

空间复杂度:O2n

DFS:

从根节点一直遍历到叶子节点,将结果树看做一个完美N叉树,节点总个数为n个,层数为lv,求叶子节点个数c

根据公式`(c ^ lv) - 1 = n`,则 `c = lv √(n + 1)`(n+1的lv次方跟)

时间复杂度:o = lv ^ (c * lv) = (n+1) ^ lv

空间复杂度:O1

测试数据

源代码-github

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wcc_chao@163.com

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值