【问题标题】:Get number of nodes at given level of JSON tree获取给定 JSON 树级别的节点数
【发布时间】:2016-07-08 22:23:47
【问题描述】:

我有一个带有子节点的 JSON 树结构,我想知道在结构的给定级别上存在多少个节点。我目前有这个递归结构:

 var getNumNodesAtLevel = function (node, curr, desired) {
        if (curr === (desired - 1)) {
            return node.children.length;
        } else {
            var children = node.children;
            children.forEach(function (child) {
                return getNumNodesAtLevel(child, curr + 1, desired);
            });
        }
    };

这不起作用 - 任何帮助将不胜感激!

【问题讨论】:

  • 您的 forEach 调用实际上并没有做任何事情,除了拨打电话。
  • JSON 只是对象的语义描述。如果它是对象形式,它只是一个对象。
  • 你的第一条评论是什么意思?
  • 如果你有一个树结构,你必须从顶部开始或者导航到顶部,如果你要确定树在某个深度处变得多宽,但是你的设计在这里没有显示条目位于根部,也无法向上导航。
  • 我对函数的调用是为节点参数传入根节点

标签: javascript json recursion


【解决方案1】:

您在此处展示的方法存在几个缺陷。

在遇到目标深度的深度时停止第一次将导致仅计算那里的第一组孩子,这只是一个子集。

使用诸如forEach之类的迭代函数将在其迭代中进行调用,但它本身不会返回值,并且在回调内部使用return的所示方法也无效。

forEach() 对每个数组元素执行一次回调函数;与 map() 或 reduce() 不同,它总是返回值 undefined 并且不可链接。典型的用例是在链的末端执行副作用。 -MDN: Array.prototype.forEach()

更好的方法是按深度分析整个树结构的宽度,完成后返回索引值。可以通过在给定深度后不递归来短路,但我在对象depths 中留下了完整的分析示例。

如下所示,这使用了一个IIFE对树进行递归,构建一个以深度为键,以宽度为值的对象,然后根据原始函数调用的输入深度返回关联的宽度。

var testObj = {
 children : [ 
  { children : [ { children : [ ] } ] },
  { children : [ ] },
  { children : [ { children : [ ] } ] }
 ]
};

var getNumNodesAtLevel = 
    function (root, depth) {
      var depths = {0:1};

      (function recurTree(node,level){
        level++;
        
        if(depths[level] == void 0){
          depths[level] = node.children.length;
        }else{
          depths[level] += node.children.length;
        }

        //optionally short circuit to avoid excessive recursion
        //if(level+1 > depth) return;
        for(var i = 0; i < node.children.length; i++){
            recurTree(node.children[i],level);  
        }
      })(root,0)
      
      return depths[depth];
    };

console.log(getNumNodesAtLevel(testObj,1));
console.log(getNumNodesAtLevel(testObj,2));

【讨论】:

    【解决方案2】:

    你很亲密。您只需将孩子的长度存储在某个地方。

    一旦达到比期望的少一级,该函数返回孩子的长度。

    树中所有更高的节点只会将从子节点收集的值加到零,然后将其传回,直到到达根节点。

    var getNumNodesAtLevel = function(node, curr, desired) {
      if (curr === (desired - 1))
        return node.children.length;
    
      var count = 0;
      node.children.forEach(function(child) {
        count += getNumNodesAtLevel(child, curr + 1, desired);
      });
      return count;
    };
    

    这种方法的问题是,当期望的层级大于树的深度或者为零(根层级,应该返回1)时,会返回0。

    要解决这个问题,您可以关闭并检查有问题的值。

    也不必每次都手动发送起始电平。

    var test = {
     children : [ 
      { children : [ { children : [ ] } ] },
      { children : [ ] },
      { children : [ { children : [ ] } ] }
     ]
    };
    
    var getNumNodesAtLevel = (function() {
    
      var getNumNodesAtLevel = function(node, curr, desired) {
        if (curr === (desired - 1))
          return node.children.length;
    
        var count = 0;
        node.children.forEach(function(child) {
          count += getNumNodesAtLevel(child, curr + 1, desired);
        });
        return count;
      };
    
      return function(root, desired) {
    
        if (desired === 0)
          return 1;
    
        var count = getNumNodesAtLevel(root, 0, desired);
        if (count === 0)
          return null; // you could throw an error here
    
        return count;
    
      };
    
    }());
    
    console.log(getNumNodesAtLevel(test, 0)); // 1
    console.log(getNumNodesAtLevel(test, 1)); // 3
    console.log(getNumNodesAtLevel(test, 2)); // 2
    console.log(getNumNodesAtLevel(test, 3)); // null
    console.log(getNumNodesAtLevel(test, 4)); // null

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-28
      • 1970-01-01
      • 1970-01-01
      • 2018-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多