从JSON创建一个树

时间:2016-11-02 05:38:46

标签: javascript tree

我是Javascript的新手,我有一些课程,但我还在学习它,我正在努力用JSON制作树。我在这里查看了其他答案,但我似乎无法理解减少,递归和jquery thingys。所以我创造了自己的功能。

但首先,我的JSON看起来像这样:

var data = [{
   "id": 51,
   "name": "root"
}, {
  "id": 54,
  "name": "app",
  "parentId": 53
}, {
  "id": 55,
  "name": "text.txt",
  "parentId": 54
}, {
 "id": 53,
 "name": "share",
 "parentId": 52
}, {
 "id": 52,
 "name": "local",
 "parentId": 51
}];

这些函数处理JSON对象:

var treeNode = function(nodeId, name) {
    var children = [];

    this.nodeId = nodeId;
    this.name = name;
    this.parentNode = null;

    this.setParent = function(parentNode) {
       this.parentNode = parentNode;
    };
    this.addChild = function(node){
       children.push(node);
       node.setParent(this);
    };
};

var Tree = function() {
  this.nodes = [];
  this.findNodeById = function(nodeId) {
     for (var i=0; i<this.nodes.length; i++) {
        if (this.nodes[i].nodeId === nodeId) {
           return this.nodes[i];
        }
   }
   return null;
  };
  this.createNode = function(nodeId, name, parentNode) {
     var node = new treeNode(nodeId, name);
     if (parentNode) {
       parentNode.addChild(node);
     }
     this.nodes.push(node);
   }
};

function createTree(data) {

  var tree = new Tree();
  var temp = [];
  for (var i=0; i<data.length; i++) {
    var inputNode = data[i];
    var parentNode = inputNode.parentId ? tree.findNodeById(inputNode.parentId) : null;
    tree.createNode(inputNode.id, inputNode.name, parentNode);
  }
 return tree.nodes;
}

然后我调用函数:createTree(data);

所以在经过多次调试尝试制作功能之后,我终于意识到我可能在某个地方犯了一个错误,因为现在54和53节点的父母没有显示我只是无法绕过我的脑袋我做错了什么,我该如何解决?有人可以帮帮我吗?

非常感谢任何建议。

1 个答案:

答案 0 :(得分:2)

您的代码一般看起来不错。问题是算法 它与插入节点的顺序直接相关。

原因

你有一棵空树 首先,插入节点#51。现在,你有一个单节点#51的树 然后尝试插入节点#54,其中parentNode#53 ...不存在。

这里

var parentNode = inputNode.parentId ? tree.findNodeById(inputNode.parentId) : null;

你调用tree.findNodeById,它遍历你的树,找不到节点53(它还没有在树中),并返回null

因此,您的第二个节点将parentNode设置为null,而不是节点#53。

解决方案

基本思想是,您始终需要确保对于每个插入的节点,其父节点已经在树中。

如何实现这个目标?

我想到的最简单的输入数据解决方案是在插入前按升序对parentNode上的数组进行排序。
它将保证您始终在父节点之后插入子节点,但它仅在节点以拓扑顺序编号时才有效。
这意味着parentId始终小于id。例如,节点5不能拥有ID为7的父级。

此处,它适用于您的输入数据:

var data = [{
   "id": 51,
   "name": "root"
}, {
  "id": 54,
  "name": "app",
  "parentId": 53
}, {
  "id": 55,
  "name": "text.txt",
  "parentId": 54
}, {
 "id": 53,
 "name": "share",
 "parentId": 52
}, {
 "id": 52,
 "name": "local",
 "parentId": 51
}];


var treeNode = function(nodeId, name) {
    var children = [];

    this.nodeId = nodeId;
    this.name = name;
    this.parentNode = null;

    this.setParent = function(parentNode) {
       this.parentNode = parentNode;
    };
    this.addChild = function(node){
       children.push(node);
       node.setParent(this);
    };
};

var Tree = function() {
  this.nodes = [];
  this.findNodeById = function(nodeId) {
     for (var i=0; i<this.nodes.length; i++) {
        if (this.nodes[i].nodeId === nodeId) {
           return this.nodes[i];
        }
   }
   return null;
  };
  this.createNode = function(nodeId, name, parentNode) {
     var node = new treeNode(nodeId, name);
     if (parentNode) {
       parentNode.addChild(node);
     }
     this.nodes.push(node);
   }
};



function createTree(data) {
  // HERE, you sort your array by parentId ASC:
  data = data.sort(function(a, b) {
    return a.parentId - b.parentId;
  });

  var tree = new Tree();
  var temp = [];
  for (var i=0; i<data.length; i++) {
    var inputNode = data[i];
    var parentNode = inputNode.parentId ? tree.findNodeById(inputNode.parentId) : null;
    tree.createNode(inputNode.id, inputNode.name,  parentNode);
  }
 return tree.nodes;
}

console.log(createTree(data));

但是,如果您的节点是随机编号的,那么您需要实施topological sorting而不是parentId的简单排序。

P.S。

顺便说一句,您可能希望使用对象映射而不是数组,以便不会每次都迭代它。它会提高O(n)次 - O(1)而不是O(n)

var Tree = function() {
  this.nodes = {};
  this.findNodeById = function(nodeId) {
     return nodes[nodeId];
  };
  this.createNode = function(nodeId, name, parentNode) {
     var node = new treeNode(nodeId, name);

     if (parentNode) {
       parentNode.addChild(node);
     }

     if (this.nodes[nodeId]) {
       throw new Error("There is already node with ID " + nodeId + " in the tree.");
     }

     this.nodes[nodeId] = node;
   }
};