如何跟踪树的所有路径,如数据结构?

时间:2016-08-29 00:31:03

标签: javascript recursion tree

假设我有一个像这样的嵌套对象:

{
  label: 'parent',
  eyeColor: 'brown',
  kids: [
    {
      label: 'kid_0',
      eyeColor: 'brown',
      kids: [
        {
          label: 'kid_0_0',
          eyeColor: 'green',
          kids: []
        },
        {
          label: 'kid_0_1',
          eyeColor: 'brown',
          kids: [
            {
              label: 'kid_0_1_0',
              eyeColor: 'brown',
              kids: []
            }
          ]
        }
      ],
    },
    {
      label: 'kid_1',
      eyeColor: 'brown',
      kids: [
        {
          label: 'kid_1_0',
          eyeColor: 'brown',
          kids: []
        }
      ],
    },
    {
      label: 'kid_2',
      eyeColor: 'green',
      kids: []
    }
  ]
};

如果我想存储所有唯一路径,我将如何递归地执行此操作?我尝试了很多尝试,但我似乎无法获得独特的路径(我的路径建立在以前的路径之上)。

所以我的预期输出是:

[
  ['parent', 'kid_0', 'kid_0_0],
  ['parent', 'kid_0', 'kid_0_1, kid_0_1_0],
  ['parent', 'kid_1', 'kid_1_0],
  ['parent', 'kid_2]
]

但是如果我想找到一个除了eyeColor之外的brown的孩子或节点时我想停止路径,那么路径就会停在那里。然后需要改变以获得以下内容:

[
  ['parent', 'kid_0', 'kid_0_1, kid_0_1_0],
  ['parent', 'kid_1', 'kid_1_0],
]

这是我当前的代码,现在错误输出最大调用堆栈的b / c。

var printPaths = function(node, color) {
  var paths = [];

  var trackPath = function(obj, feature, path) {
    if (obj.eyeColor === 'brown') {
      path.push(node.label);
    } else if (obj.eyeColor !== 'brown') {
      paths.push(path);
    } else if (obj.kids.length === 0) {
      paths.push(path);
    }

    for (var i = 0; i < obj.kids.length; i++) {
      trackPath(obj.kids[i], feature, path)
      path.pop();
    }
  };

  trackPath(node, color, []);
  return paths; 
}

3 个答案:

答案 0 :(得分:1)

你的方法很好,唯一的问题是assignment or argument passing doesn't copy arrays。在递归中引入slice()调用:

function printPaths(node, color) {
  var paths = [];

  function trackPath(obj, feature, path) {
    if (obj.eyeColor !== feature) { // found target
      paths.push(path);
      return;
    } // else continue
    path.push(obj.label);

    for (var i = 0; i < obj.kids.length; i++) {
      trackPath(obj.kids[i], feature, path.slice());
//                                        ^^^^^^^^
    }
  }

  trackPath(node, color, []);
  return paths;
}

答案 1 :(得分:0)

这是我的方法,我必须重写你的逻辑以及使用切片

进行数组复制
var printPaths = function(node, color) {
  var paths = [];

  var trackPath = function(obj, feature, path) {
    //debugger;
    path.push(obj.label);

    if (obj.eyeColor === 'brown') {
      if (obj.kids.length == 0) {
        paths.push(path.slice());
      }
      else {
        for (var i = 0; i < obj.kids.length; i++) {
          trackPath(obj.kids[i], feature, path);
        }
      }
    } 


    path.pop();
  };

  trackPath(node, color, []);
  return paths; 
}

答案 2 :(得分:0)

这是我最终开始工作的解决方案。我得到了@Bergi的帮助,但他的解决方案并没有完全符合我的需要。这个解决方案超越了我写的所有测试。

var printPaths = function(node, color) {
  var paths = [];

  var trackPath = function(obj, feature, path) {    
    // if the current node has the desired property, push that
    // to the current path, then continue checking checking
    // if there are any children (two if statements down)
    if (obj.eyeColor === feature) {
      path.push(obj.label);
    } 
    // if we encounter a path that isn't our desired property,
    // don't push the current node on to the current path, but instead
    // just push the failed path, and return, so that it doesn't
    // continue to check
    if (obj.eyeColor !== feature) {
      paths.push(path);
      return;
    }
    // if we're at a leaf node, i.e we had a full successful path
    // (everyone had brown eyes)
    if (obj.kids.length === 0) {
      paths.push(path);
    }

    for (var i = 0; i < obj.kids.length; i++) {
      trackPath(obj.kids[i], feature, path.slice())
    }
  };

  trackPath(node, color, []);
  return paths; 
}