【问题标题】:How to trace all paths of a tree like data structure?如何像数据结构一样跟踪树的所有路径?
【发布时间】:2016-08-29 00:31:03
【问题描述】:

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

{
  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; 
}

【问题讨论】:

  • 请向我们展示您的尝试,即使它们不起作用。
  • @Bergi 我发布了我损坏的代码。我犹豫要不要发布它,因为我想看看更有经验的程序员如何解决这个问题。
  • 这种方法看起来很好——除了arrays are reference values and need to be copied explicitly。所以放弃.pop() 调用,而是将递归调用改为trackPath(obj, feature, path.slice())
  • @Bergi 你的意思是obj.kids[i]?我添加了.slice(),但后来我得到了[ [ 'parent', 'parent' ], [ 'parent', 'parent', 'parent' ], [ 'parent', 'parent' ] ]。它没有像我预期的那样做。
  • 不,我的意思是path。它指的是到处都是完全相同的数组,指的是您在最初的trackPath(node, color, []); 调用中创建的数组。

标签: javascript recursion tree


【解决方案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;
}

【讨论】:

  • @AlanH:feature 不同,经过我的编辑,它的行为应该与您的答案相同
【解决方案2】:

这是我的方法,我必须重写你的逻辑以及使用 slice 复制数组

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; 
}

【讨论】:

    【解决方案3】:

    这是我最终开始工作的解决方案。我得到了@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; 
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多