繁体   English   中英

在树中递归查找任意节点路径

[英]Recursively find arbitrary node path in tree

我有一棵由以下结构组成的对象树:

interface Node {
  name: string;
  children?: Node[];
}

例如, { name: "foo", children: [ { name: "bar" } ] }是有效树。 我正在尝试获取任意节点的地址,该地址可以是叶子,作为到达它的路径的数组返回,该节点将通过对象引用进行比较。 给定示例,我具有以下结构:

var data = {
  name: "Languages",
  children: [{
    name: "Functional",
    children: [
      { name: "OCaml" },
      { name: "Haskell" },
      { name: "Erlang" }
    ]
  }, {
    name: "Imperative",
    children: [
      { name: "BASIC" },
      { name: "Clipper" }
    ]
  }]
};

期望,例如,如果我有一个存储在名为ocaml的变量中的OCaml引用,该变量恰好指向内存中的该引用,则将返回步骤数组以及到达该引用的路径,在这种情况下, [0, 0]

我已经可以找到对象,但是我不能存储先前的索引,因为这是不确定的:

var tree = function(struct, cmp) {
  if (struct.children) {
    var lookup = [];
    for (var i = 0; i < struct.children.length; i++) {
      lookup.push(tree(struct.children[i], cmp));
    }
    return lookup;
  } else {
    if (struct === cmp) {
      return "PASS";
    }
    return "FAIL";
  }
}

我可以找到该元素,但是如何存储以前的索引以从基数中获取它呢?

尝试跟踪局部作用域变量中的路径将不起作用,因为每个递归调用都会创建一个新作用域。 假设您想要的东西与您已经拥有的东西非常相似,则相当小的更改是使索引的查找路径成为该方法的返回值。 递归调用的基本情况(当没有子节点时)返回[] (找到)或null (找不到)。

var tree = function(struct, cmp) {
    if (struct === cmp) {
        // `cmp` is found at current `struct`.
        return [];
    } else if (struct.children) {
        for (var i = 0; i < struct.children.length; i++) {
            var path = tree(struct.children[i], cmp);
            if (path !== null) {
                // `cmp` is found at `path` in `struct.children[i]`,
                // so prefix `i` to `path` to get the path in `struct`.
                path.unshift(i);
                return path;
            }        
        }
    }
    // `cmp` not found in this branch of the tree.
    return null;
};

console.log(tree(data, data.children[0].children[0])); // outputs [0, 0]
console.log(tree(data, data.children[0].children[2])); // outputs [0, 2]
console.log(tree(data, data.children[1].children[1])); // outputs [1, 1]

我将data包装在一个数组中。 对于所有节点,您可以将引用存储在一个对象中,例如

var lookUp = {
    'OCaml':getNode(data, 'OCaml'),
    'BASIC': getNode(data, 'BASIC')
};

或者,您可以通过遍历对象来构建参考。

 var data = [{ name: "Languages", children: [{ name: "Functional", children: [ { name: "OCaml" }, { name: "Haskell" }, { name: "Erlang" } ] }, { name: "Imperative", children: [ { name: "BASIC" }, { name: "Clipper" } ] }] }]; function getNode(array, name) { function findNode(a, i, o) { if (a.name === name) { node = o[i] return true; } return Array.isArray(a.children) && a.children.some(findNode); } var node; array.some(findNode); return node; } var lookUp = { 'OCaml':getNode(data, 'OCaml'), 'BASIC': getNode(data, 'BASIC') }; lookUp.BASIC.name = 'Basic'; document.write('<pre>' + JSON.stringify(data, 0, 4) + '</pre>'); 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM