【题目】将一维数组转换成树状结构
【描述】
假设有一个包含多个对象的数组 arr,每个对象都有两个属性:id 和 parentId。其中,id 表示该对象的唯一标识符,parentId 表示该对象所属的父级对象的 id。如果该对象没有父级,则 parentId 为 null。
例如,对于下面的数组:
const arr = [
{ id: 1, parentId: null },
{ id: 2, parentId: 1 },
{ id: 3, parentId: 1 },
{ id: 4, parentId: 2 },
{ id: 5, parentId: 2 },
{ id: 6, parentId: 3 },
{ id: 7, parentId: 3 },
];
可以看出,该数组描述了一个树形结构,其中 id 是节点的标识符,parentId 是该节点在树中的父节点的标识符。例如,节点 1 没有父节点,因此其 parentId 为 null;节点 4 和节点 5 的父节点都是节点 2。
请编写一个函数 buildTree(arr),将以上数组转换为一个树形结构,并返回树的根节点(即 parentId 为 null 的节点)。
要求:
- 返回的树形结构应该是一个对象,其包含
id和children两个属性,id表示节点的标识符,children表示该节点的子节点数组。 - 如果某个节点没有子节点,则其
children属性应该为空数组。 - 如果输入的数组中不存在根节点(即
parentId为null的节点),则返回null。
例如,对于上面的数组 arr,调用 buildTree(arr) 应该返回以下对象:
{
id: 1,
children: [
{
id: 2,
children: [
{ id: 4, children: [] },
{ id: 5, children: [] }
]
},
{
id: 3,
children: [
{ id: 6, children: [] },
{ id: 7, children: [] }
]
}
]
}
请实现函数 buildTree(arr)。
【答案】
function buildTree(arr) {
const nodeMap = {};
let root;
// 构建节点映射表
arr.forEach(obj => {
const { id, parentId } = obj;
if (!nodeMap[id]) {
nodeMap[id] = { id, children: [] };
}
if (parentId === null) {
root = nodeMap[id]; // 将根节点保存为 root
} else {
if (!nodeMap[parentId]) {
nodeMap[parentId] = { id: parentId, children: [] };
}
nodeMap[parentId].children.push(nodeMap[id]);
}
});
return root || null; // 返回根节点,如果没有根节点则返回 null
}
// 测试样例
const arr = [
{ id: 1, parentId: null },
{ id: 2, parentId: 1 },
{ id: 3, parentId: 1 },
{ id: 4, parentId: 2 },
{ id: 5, parentId: 2 },
{ id: 6, parentId: 3 },
{ id: 7, parentId: 3 },
];
const tree = buildTree(arr);
console.log(tree);
这个解法使用一个对象 nodeMap 来构建节点的映射表,并找到根节点。在遍历原始数组时,如果某个节点的 parentId 为 null,则将该节点设置为根节点 root。对于其他节点,将它们添加到对应的父节点的 children 数组中。最后返回根节点。这个解法可以正确地构建出树形结构,并输出根节点。如果没有根节点,则返回 null。