Js 将数组按父子关系转换为对象树

这是一道遇到过两次的前端笔试题,第一次是在哪里记不清了,第二次是在今天上午多益网络的笔试中,两次试题的具体内容稍微有差别,因为时间和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]);

猜你喜欢

转载自blog.csdn.net/qq_33594380/article/details/82462701