Clever use of references to the array into a tree array

Foreword

I need to make a program made a tree menu front end, a rear end of the data returned is parallel list, list each element is an object, such as list[0]a value {id: 1, fid: 0, name: 一级菜单}, each element specifies the parent element , generated menu unlimited level of nesting. Start looking for a plug-ins need to manually generate good tree array pass in order to use (although later found a UI framework that can be transferred directly into the list, and only need to specify the id fid), but then thought for a long time failed to correct written, carefully thought for a moment when it is empty down, organized into notes for the late review.

Ready to work

Because it is the front-end processing, so this implementation language for the js.

Below, there is a parallel list file and not in a list of root root:

var s = [
  { id: 1, fid: 0, name: "第一级菜单1" },
  { id: 2, fid: 0, name: "第一级菜单2" },
  { id: 3, fid: 1, name: "第二级菜单1.1" },
  { id: 4, fid: 1, name: "第二级菜单1.2" },
  { id: 5, fid: 2, name: "第二级菜单2.1" },
  { id: 6, fid: 3, name: "第三级菜单1.1.1" },
  { id: 7, fid: 3, name: "第三级菜单1.1.2" },
  { id: 8, fid: 4, name: "第三级菜单1.2.1" },
  { id: 9, fid: 4, name: "第三级菜单1.2.2" },
  { id: 10, fid: 6, name: "第四级菜单1.1.1.1" },
  { id: 11, fid: 6, name: "第四级菜单1.1.1.2" },
  { id: 12, fid: 9, name: "第四级菜单1.2.2.1" },
  { id: 13, fid: 9, name: "第四级菜单1.2.2.2" },
  { id: 14, fid: 0, name: "第一级菜单3" }
]

var root = { id: 0, fid: 0, name: "根菜单" };

Need to organize to look similar to the following, if the node has no children, no node attributes:

{
    id: xx,
    fid: xx,
    name: xx,
    node: [
        id: xx,
        fid: xx,
        name: xx,
        node: [...]
    ]
}

shuffle algorithm requires a list to disrupt the order, the algorithm will affect the original array:

function shuffle(a) {
  var len = a.length;
  for (var i = 0; i < len; i++) {
    var end = len - 1;
    var index = (Math.random() * (end + 1)) >> 0;
    var t = a[end];
    a[end] = a[index];
    a[index] = t;
  }
};

JSON serialization achieved using deep copy of the array:

function deepCopy(arr) {
  return JSON.parse(JSON.stringify(arr));
}

Using a simple way to determine the preliminary results are correct:

function check(node) {
    return JSON.stringify(node).match(/菜单/g).length;
}

Recursive

[Thinking]

For this problem, because they do not know in the end how many layers you want to cycle, it is possible to use recursion in a very convenient way to get around.

【step】

1. traversal current listing identify incoming fid parent element id node, and the node linked to a parent element;

2. Each find a node to delete this element from the current list (otherwise how recursion termination);

3. For each child node, repeating the above steps, the sub-node as the parent node of the next level continues to find the children of the node.

It can be seen as the worst time complexity O(n!).

【achieve】

function arr2tree(arr, father) {
  // 遍历数组,找到当前father的所有子节点
  for (var i = 0; i < arr.length; i++) {   
    if (arr[i].fid == father.id) {
      // 这里是有子节点才需要有node属性(也就是说有node里绝不会为空list)
      if (!father.node) { 
        father.node = [];
      }
      var son = arr[i];
      father.node.push(son);
      arr.splice(i, 1); // 删除该节点,当list为空的时候就终止递归
      i--; // 由于删除了i节点,所以下次访问的元素下标应该还是i
    }
  }
  // 再对每一个子节点进行如上操作
  if (father.node) { // 需要先判断有没有子节点
    var childs = father.node;
    for (var i=0; i<childs.length; i++) {
      arr2tree(arr, childs[i]); // 调用递归函数
    }
    // 用于按名称进行排序,如果不强调顺序可以去掉
    father.node.sort(function (a, b) {
      return a.name > b.name;
    })
  }
}

【test】

shuffle(s); // 打乱数组
var arr = deepCopy(s); // 拷贝一份,避免对原数组进行修改
arr2tree(arr, root);
console.log(check(root)); // 预期输出15
console.log(root); // 手工检查输出是否正确

Do not use recursion

[Thinking]

When the amount of data when using recursion and easy because of out of memory and can not run, there is no way not to use recursion it? Can not be directly used to cycle to get it? Can you walk through the side elements directly to this element into the correct position, so that you can save a lot of things. Can use a hash table (dictionary / objects) to store these elements, a key (attribute name) is the id element, this can be directly determined traversed parent element the current element is not in the hash table inside.

Suddenly, I thought of a feature - quote , JS objects are referenced in , even if I have a target in a push into a list, I'm in the face of any changes will be a object reflected in the list . That is to say, a I element linked to the corresponding parent element f, and I have found when a child element of the element b in the back, I b of the sub-element linked to the a, f will be in a mount b have the same elements.

【step】

1. Create a temp for temporary target information. Traversing the list in the current access elements in a temp was added (named Attribute Object id, attribute value of the object);

2. Find whether there is a child node in the temp, any child will be linked to the node a;

3. find whether there is a parent node temp, some words will be linked to a parent node;

Can be seen, the time complexity is O (n ^ 2 ^), the spatial complexity is not too high, this method does not modify the original array.

【achieve】

function arr2tree2(arr, root) {
  var temp = {};
  temp[root.id] = root;
  for (var i = 0; i < arr.length; i++) {
    // 插入一个新节点,后面对该节点的修改都会同步到该节点的父节点上
    temp[arr[i].id] = arr[i];
    // 查找是否有子节点
    var keys = Object.keys(temp);
    for (var j = 0; j < keys.length; j++) {
      if (temp[keys[j]].fid == arr[i].id) {
        temp[arr[i].id].node ? "" : temp[arr[i].id].node = [];
        temp[arr[i].id].node.push(temp[keys[j]]); // 将该子节点挂到当前节点的node上
      }
    }
    // 查找是否有父节点
    if (temp[arr[i].fid]) {
      temp[arr[i].fid].node ? "" : temp[arr[i].fid].node = [];
      temp[arr[i].fid].node.push(arr[i]); // 将当前节点挂到父节点的node上
    }
  }
  return temp;
}

【test】

shuffle(s); // 打乱数组
var result = arr2tree2(s, root);
console.log(check(result[root.id])); // 预期输出15
console.log(result[root.id]); // 手工检查输出是否正确

to sum up

I usually do most of the project is not related to the algorithm, usually adhering to the cycle can also be addressed to use recycled resolved, you can see that the algorithm is very important for programmers, this article is only personal thoughts are welcome explore together.

Guess you like

Origin www.cnblogs.com/loveshes/p/11877799.html