这是一道遇到过两次的前端笔试题,第一次是在哪里记不清了,第二次是在今天上午多益网络的笔试中,两次试题的具体内容稍微有差别,因为时间和IDE 的原因都没能解出正确答案。事后又花点时间捣鼓一下,整理出两种解法,记录在这里。
1. 问题的输入与输出
首先来看一下这个问题的输入和输出:
// 输入
var nodes = [
{id: 10, title: 'dw10', parentId: 4},
{id: 2, title: 'dw2', parentId: 0},
{id: 4, title: 'dw4', parentId: 2},
{id: 12, title: 'dw12', parentId: 2},
{id: 8, title: 'dw8', parentId: 4}
];
// 输出
{
"id": 2,
"title": "dw2",
"parentId": 0,
"children": [
{
"id": 12,
"title": "dw12",
"parentId": 2
},
{
"id": 4,
"title": "dw4",
"parentId": 2,
"children": [
{
"id": 8,
"title": "dw8",
"parentId": 4
},
{
"id": 10,
"title": "dw10",
"parentId": 4
}
]
}
]
}
2. 解法一:广度优先搜索
第一种解法的步骤如下:
(1)首先,按照每一项的parentId 数值给输入数组排序。
(2)将排序后的数组的第一条数据作为根元素,遍历数组,比较当前记录的parentId 和结果对象中的id 依次将剩下的数据插入到合适的位置上,在寻找合适位置的过程中使用的是广度优先搜索的方法。
此种方法的时间复杂度较高,代码量颇大,实现代码如下:
var nodes = [
{id: 10, title: 'dw10', parentId: 4},
{id: 2, title: 'dw2', parentId: 0},
{id: 4, title: 'dw4', parentId: 2},
{id: 12, title: 'dw12', parentId: 2},
{id: 8, title: 'dw8', parentId: 4}
];
function findPos(obj, id) {
// 广度优先搜索遍历当前对象
var queue = [], temp;
if(obj.id === id) {
return obj;
}
queue.push(obj.children);
while(queue) {
temp = queue.shift();
var res = findChildIndex(id, temp);
if(res) {
return res;
}
for(var i = 0; i < temp.length; i++) {
queue.push(temp[i]);
}
}
}
// 判断一个数字是否在children 列表内
function findChildIndex(id, arr) {
if(arr.id && id === arr.id) {
return arr;
}
for(var i = 0; i < arr.length; i++) {
if(id === arr[i].id) {
return arr[i];
}
}
return null;
}
// sort
function cmp(a, b) {
return a.parentId - b.parentId;
}
nodes.sort(cmp);
var resObj = nodes[0];
for(var i = 1, len = nodes.length; i < len; i++) {
var findRes = findPos(resObj, nodes[i].parentId);
if(findRes) {
if(!findRes.children) {
findRes.children = [];
}
findRes.children.push(nodes[i]);
}
}
console.log(resObj);
3. 解法二:从后向前
在控制时间复杂度的情况下,上面提到的方法就无法达到要求。于是又开始思考第二种方法,排序后从后向前遍历数组。如果把最终的对象想象成一颗树的话,这个方法就相当于从叶子节点开始到根节点逐渐建立一棵完整的树。
与上一个方法相比,该方法时间复杂度较低,且代码量不大,实现代码如下:
var nodes = [
{id: 10, title: 'dw10', parentId: 4},
{id: 2, title: 'dw2', parentId: 0},
{id: 4, title: 'dw4', parentId: 2},
{id: 12, title: 'dw12', parentId: 2},
{id: 8, title: 'dw8', parentId: 4}
];
// sort
function cmp(a, b) {
return a.parentId - b.parentId;
}
nodes.sort(cmp);
var midObj = {};
// 从后向前遍历
for(var i = nodes.length - 1; i >= 0; i--) {
var nowPid = nodes[i].parentId;
var nowId = nodes[i].id;
// 建立当前节点的父节点的children 数组
if(midObj[nowPid]) {
midObj[nowPid].push(nodes[i]);
} else {
midObj[nowPid] = [];
midObj[nowPid].push(nodes[i]);
}
// 将children 放入合适的位置
if(midObj[nowId]) {
nodes[i].children = midObj[nowId];
delete midObj[nowId];
}
}
console.log(midObj[0][0]);