递归遍历二叉树Javascript的所有嵌套子节点

Posted

技术标签:

【中文标题】递归遍历二叉树Javascript的所有嵌套子节点【英文标题】:Recursion to traverse all the nested child nodes of Binary Tree Javascript 【发布时间】:2016-06-06 01:11:40 【问题描述】:

我正在玩一棵二叉树。我正在尝试使用递归来查找所有嵌套子项的值并将所有值推送到数组中。我从左边的树开始看它是否有效。我试图打电话给childrenArray(),但控制台说 childrenArray() 没有定义。当我询问if (typeof BinaryTree.prototype.childrenArray === 'function') 时,它返回true。请教我并告诉我为什么我无法执行我的代码?

var Tree = function(value) 
  if (!(this instanceof Tree)) 
    return new Tree(value);
  
  this.value = value;
  this.children = [];
;

Tree.prototype.addChild = function(value) 
  var child = new Tree(value);
  this.children.push(child);
;

Tree.prototype.contains = function(value) 
  if (this.value === value) 
    return true;
   else 
    for (var i = 0; i < this.children.length; i++) 
      if (this.children[i] && this.children[i].contains(value)) 
        return true;
      
    
    return false;
  
;


var BinaryTree = function(value) 
  if (!(this instanceof BinaryTree)) 
    return new BinaryTree(value);
  
  Tree.call(this, value);
;
BinaryTree.prototype = Object.create(Tree.prototype);

BinaryTree.prototype.addChild = function(value) 
  if (value < this.value) 
    if (this.children[0] === undefined) 
      this.children[0] = new BinaryTree(value);
    
    this.children[0].addChild(value);
   else if (value > this.value) 
    if (this.children[1] === undefined) 
      this.children[1] = new BinaryTree(value);
    
    this.children[1].addChild(value);
  
;
BinaryTree.prototype.contains = function(value) 
  if (value < this.value) 
    if (this.children[0] === undefined) 
      return false;
    
    return this.children[0].contains(value);
   else if (value > this.value) 
    if (this.children[1] === undefined) 
      return false;
    
    return this.children[1].contains(value);
  
;

var a = new BinaryTree();
a.value = 10;
a.addChild(4);
a.addChild(11);
a.addChild(3);

BinaryTree.prototype.childrenArray = function() 
  var results = [];

  if (this.value) 
    results.push(this.value);
  

  if (this.children[0].length === 0) 

    return results;
  

  for (var i = 0; i < this.children[0].children.length; i++) 
    if (this.children[i].value) 
      results.push(this.children[i].value);
      return this.childrenArray();
    
  

;

a.childrenArray();

【问题讨论】:

你打电话给childArray,这似乎是未定义的。 您定义了childrenArray(),但没有定义childArray()。认为您混淆了两者。 评论因重复而被撤销 嘿,我修好了,但现在问题是最大溢出。 您是否将childArray 替换为this.childrenArray?如果您在同一个对象上调用 childrenArray,它将开始无限递归。即便如此,好好看看你打算如何将results从一个递归级别传递到另一个级别。 【参考方案1】:

正如 @melpomene 提到的,您正在调用 childArray,但您没有在任何地方定义它。我假设return childArray(); 行错误地结束了,您可能打算递归地为root 的左孩子返回childrenArray

我想提一下你的循环本身(没有递归调用):

for(var i = 0; i < this.children[0].children.length; i++)  // <-- you are iterating over the children of root's left child
     if(this.children[i].value)  // <-- but you are accessing root's current child
        results.push(this.children[i].value);
     

有点混乱。您正在迭代 root 的左孩子的孩子 children[0].children,但在每次迭代中,您检查 root 的孩子 自己 children[i] 是否有一个值,然后推送该值. 这是不正确的,并且会中断,例如,如果根只有一个左孩子同时有两个孩子(i 将超出范围)。


以下是解决此问题的方法。在您的情况下,打印左树的递归可以分为以下几种情况:

    如果当前节点没有值,返回一个空数组 Else 如果当前节点没有子节点,则返回一个只包含当前值的数组 否则,如果当前节点有左子节点,则在其上递归运行childrenArray,并将结果添加到results 数组中

这就是它的样子:

BinaryTree.prototype.childrenArray = function() 
  var results = [];

  // case 1:
  if (this.value === undefined) 
    return results;
  

  // case 2:
  results.push(this.value);
  if (this.children.length === 0) 
    return results;
  

  // case 3:
  var leftChild = this.children[0];
  if (leftChild) 
    results = results.concat(leftChild.childrenArray());
  

  /* add code here for the right child to complete your function */

  return results;
;

完整示例:

var BinaryTree = function(value) 
  this.value = value;
  this.children = [];
;

BinaryTree.prototype.addChild = function (value) 
  if (value < this.value) 
    if (this.children[0] === undefined) 
      this.children[0] = new BinaryTree(value);
    
    this.children[0].addChild(value);
   else if (value > this.value) 
    if (this.children[1] === undefined) 
      this.children[1] = new BinaryTree(value);
    
    this.children[1].addChild(value);
  
;

BinaryTree.prototype.childrenArray = function() 
  var results = [];

  // case 1:
  if (this.value === undefined) 
    return results;
  

  // case 2:
  results.push(this.value);
  if (this.children.length === 0) 
    return results;
  

  // case 3:
  var leftChild = this.children[0];
  if (leftChild) 
    results = results.concat(leftChild.childrenArray());
  

  /* add code here for the right child to complete your function */

  return results;
;

var a = new BinaryTree(10);
a.addChild(4);
a.addChild(11);
a.addChild(3);

console.log(a.childrenArray()); // [10, 4, 3]

最后一件事,根据您的插入逻辑(如果较小则插入左侧,如果较大则插入右侧),您正在构建 Binary Search Tree 而不是 Binary Tree。二叉树不遵循任何特定的插入逻辑。请查看this question 进行澄清

【讨论】:

谢谢!你能解释一下为什么我们使用 concat 而不是 push。为什么它在 this -> this.children[0] = value: 1: child:[]; 时连接值它是一个对象。因为我以为 this.children[0].value 会得到值。 不客气。由于childrenArray() 返回一个数组,并且您想将该数组的内容推送到results 数组中,因此执行results.push(content) 会将整个数组作为单个元素添加到results 中,但您想要数组中的所有元素反而。 [].concat 将两个数组组合成一个数组,这就是你想要的。

以上是关于递归遍历二叉树Javascript的所有嵌套子节点的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript二叉树的递归遍历方法

二叉树的递归遍历与非递归遍历-javascript

遍历n个节点能够形成的所有二叉树

递归遍历二叉树

二叉树的层序遍历(递归方式)

二叉树中序遍历(递归和非递归)算法C语言实现