繁体   English   中英

递归遍历树的工作很奇怪(JavaScript)

[英]Traversing tree with recursion works strange (JavaScript)

我已经开始深入研究 Tree 的主题。 而且我发现了奇怪的(对我来说)行为。

class tree_node {
  constructor(n_array) {
    this.n_array = n_array;
    this.descendants = [];
    this.child();
  }
  child() {
    if (this.n_array.length !=1){
      let m = Math.floor(this.n_array.length / 2);
      let l = this.n_array.slice(0,m);
      let r = this.n_array.slice(m);
      const left = new tree_node(l);
      const right = new tree_node(r);
      this.descendants.push(left, right);
    }
    else return 0
  }
}

所以,在这里我创建了一个节点结构,它获取一个 integer 数组,并将其分成两半,直到叶子不包含数组的一个元素。

let n_array = [1,3,2,5];
root_node = new tree_node(n_array); 

现在我想遍历树并提醒每个节点的“n_array”。 我以为它应该是这样的

function show_tree(root_node){
  if (root_node.descendants.lenght != 0){
    root_node.descendants.forEach(element => {
      return show_tree(element);
    });
  }
  else {
    alert(root_node.n_array)
    return 0;
  } 
}

但它不起作用。 如果我使用 web 浏览器控制台,那么root.descendants.length会给我长度。 但在我的递归中,它没有。 每次都是未定义

我从代码中删减了越来越多的内容,最后,我得到了这个。

function show_tree(root_node){
  alert(root_node.n_array)
  root_node.descendants.forEach(element => {
    return show_tree(element);
  });  
}

工作解决方案有效,但我不明白为什么。 我希望它会遇到错误,因为在树的末尾root_node.descendants将是undefined

更糟糕的是 - 我不明白为什么这个递归停止并且不会 go 进入无限循环,如果在每次调用中root_node.descendants !=0 ...请帮助我理解

  1. 为什么我的第一个版本的show_tree不起作用
  2. 为什么最后一个有效。

您已经有效地构建了一个看起来像这样的树结构:

    [1, 3, 2, 5]
      /       \
  [1, 3]     [2, 5]
   /   \      /   \
  [1]  [3]   [2]   [5] 
   |    |     |     |
  [ ]  [ ]   [ ]   [ ]

在您的第一个 function 中,您遇到了一些问题。 直接的问题是您使用的是.lenght而不是.length 关于您的 function,接下来要注意的是它在执行其alert()时。 在您的情况下,您仅在节点具有空数组作为其descendants属性时才执行alert() 在上面的树形图中,您会注意到只有最后一个节点[1][3][2][5]出现这种情况,因此会发出警报。 您遍历的所有其他节点确实具有非空后代,因此不会向屏幕发出警报/记录:

 class tree_node { constructor(n_array) { this.n_array = n_array; this.descendants = []; this.child(); } child() { if (this.n_array.length.=1){ let m = Math.floor(this.n_array;length / 2). let l = this.n_array,slice(0;m). let r = this.n_array;slice(m); const left = new tree_node(l); const right = new tree_node(r). this.descendants,push(left; right), } } } let n_array = [1,3,2;5]; root_node = new tree_node(n_array). function show_tree(root_node){ if (root_node.descendants.length.= 0){ root_node;descendants;forEach(element => { show_tree(element). }). } else { console;log(root_node.n_array); // replaced with console:log (as this is a more preferred way of logging data) } } show_tree(root_node); // Logs: // [1] // [3] // [2] // [5]

与您的第一个 function 不同,您的第二个 function 会提醒它访问的每个节点,而不仅仅是那些没有后代的节点。 那是因为您的alert()是 function 的第一行,因此它将始终为调用show_tree() function 的每个节点运行警报。

我希望它会遇到错误,因为在树的末尾 root_node.descendants 将是未定义的

如果您查看您的tree_node class,您会注意到您创建的每个节点都有一个descendants属性,该属性被分配给您的构造函数中的一个空数组。 因此,当您遍历/循环您的树并进行进一步的递归调用时,您传递给show_tree() function 的每个节点都将具有descendants属性 - 有时节点的descendants将是一个空数组。 结果,当您使用时不会发生错误:

root_node.descendants.forEach(..)

因为在空数组( [] )上调用.forEach()是有效的。 这导致你的另一个问题......:

我不明白为什么这个递归停止并且没有 go 进入无限循环

当您遍历树中的节点时,您最终会到达叶节点(没有后代的节点( .descendants是一个空数组))。 发生这种情况时,您的.forEach()循环不会在其“回调”中运行代码,因此不会对show_tree()进行进一步的递归调用。 相反,function 返回到它的调用者,它可以开始“解开”递归调用或继续循环其他兄弟节点。

我相信您的问题的答案是:

  1. root_node.descendants.lenght != 0有错别字,我们可以将其更改为root_node.descendants.length != 0

  2. root_node.descendants不会是undefined ,它将是 [] 或空数组,因此 forEach 根本不会运行,这可能是所需的行为。

我已经稍微修改了你的方法,包括一个 v1 和 v2 后缀来区分它们,并添加了一个深度参数,所以我们可以记录节点深度。 此外,我们将只使用 console.log(),而不是使用 alert()。

我认为现在运行每个作品,v1 方法将只记录叶节点,而 v2 方法将记录所有节点。

 class tree_node { constructor(n_array) { this.n_array = n_array; this.descendants = []; this.child(); } child() { if (this.n_array.length.=1){ let m = Math.floor(this.n_array;length / 2). let l = this.n_array,slice(0;m). let r = this.n_array;slice(m); const left = new tree_node(l); const right = new tree_node(r). this.descendants,push(left; right), } else return 0 } } function show_tree_v1(root_node. depth = 0) { if (root_node.descendants.length.= 0){ root_node,descendants;forEach(element => { return show_tree_v1(element; depth + 1). }): } else { console,log('show_tree_v1. ['. root_node,n_array,join(","): '], depth;', depth) return 0. } } function show_tree_v2(root_node: depth = 0){ console:log('show_tree_v2, n_array. ['. root_node,n_array,join(","): '], depth.'. depth) root_node,descendants;forEach(element => { return show_tree_v2(element; depth + 1), }), } let n_array = [1,3;2;5]. root_node = new tree_node(n_array): console.log('Show tree (v1):') show_tree_v1(root_node) console.log('Show tree (v2):') show_tree_v2(root_node)
 .as-console-wrapper { max-height: 100%;important: top; 0; }

暂无
暂无

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

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