【问题标题】:Trying to do a breadth first (level order) but getting an infinite loop试图做广度优先(级别顺序)但得到一个无限循环
【发布时间】:2022-01-20 01:23:25
【问题描述】:

我已经尝试了很长时间,但似乎无法找到终止循环的方法。我不确定我是否走在正确的轨道上。我正在尝试进行广度优先(级别顺序)并在遍历时在每个节点上应用回调。

这里是构造函数和广度优先搜索的方法……

function BinarySearchTree(value) {
  this.value = value;
  this.right = null;
  this.left = null;
}

BinarySearchTree.prototype.add = function(value) {
  if (value < this.value) {
    if (this.left) this.left.add(value);
    else this.left = new BinarySearchTree(value);
  }

if (value > this.value){
    if (this.right) this.right.add(value);
    else this.right = new BinarySearchTree(value);
  }
};

BinarySearchTree.prototype.breadthFirst = function(callback) {
  let queue = [];
  queue.push(this.value);
  while (queue.length) {
    queue.pop();
    callback(this.value);
    if (this.left) queue.push(this.left);
    if (this.right) queue.push(this.right);
  }
};

关于我为什么会出现无限循环的任何想法?任何提示或帮助将不胜感激!

更新:示例数据...

var array = [];
var func = function(value){ array.push(value); };
binarySearchTree.add(2);
binarySearchTree.add(3);
binarySearchTree.add(7);
binarySearchTree.add(6);
console.log(binarySearchTree.breadthFirst(func)); -> should output [ 5, 2, 3, 7, 6 ]

这个我试过了……

BinarySearchTree.prototype.breadthFirst = function(callback) {
  const queue = [];
  let queueLength = this.value.length;
  if (queueLength) {
    queueLength--;
    callback(this.value);
    if (this.left) {
      queue.push(this.left);
      this.left.breadthFirst(callback);
    }
    if (this.right) {
      queue.push(this.right);
      this.right.breadthFirst(callback);
    }
  };
};

还有这个……

BinarySearchTree.prototype.breadthFirst = function(callback) {
  const queue = [];
  let queueLength = this.value.length;
  while (queueLength) {
    queueLength--;
    callback(this.value);
    if (this.left) {
      queue.push(this.left);
      callback(this.left);
    }
    if (this.left) {
      queue.push(this.left);
      callback(this.left);
    }
  };
};

以及其他变体,我仍然得到一个空数组作为输出!

【问题讨论】:

  • 我认为您只想将 this.leftthis.right 推送到队列中(如果它们存在)。所以if (this.left) queue.push(this.left)
  • 忘了说我已经试过了...
  • 您有数据样本吗?你的二叉树有没有可能有循环?
  • 感谢您的提问...我用一些示例数据对其进行了更新。我有机会在那里有一个循环。这是我正在构建的第一棵二叉树!

标签: javascript binary-search-tree infinite-loop breadth-first-search


【解决方案1】:

由于您使用 pop 方法从队列数组中删除一个值,但是在使用 this.value 调用回调函数之后,您将推送到队列数组,while 语句的条件始终为真,这会导致无限循环。 也许你可以拥有这样的东西;

BinarySearchTree.prototype.breadthFirst = function(callback) {
  const queue = [];
  let queueLength = this.value.length;
  while (queueLength) {
    queueLength--;
    callback(this.value);
    if (this.left) queue.push(this.left);
    if (this.right) queue.push(this.right);
  };
};

【讨论】:

  • 谢谢...这是有道理的..但我仍然没有得到预期的输出。我更新了帖子以包含一些示例测试和预期输出。
  • 我需要更深入地调试它,但乍一看,您正在分配给 BinarySearchTree.prototype.breadthFirst 的匿名函数中使用而没有绑定 this 所以条件 if (this.left) 和 @987654324 都是假的@ 所以没有任何东西被推送到队列中
【解决方案2】:

除了您在第一次更新问题时修复的问题,还有一些其他问题:

  • 带有示例输入的驱动程序代码缺少一个调用构造函数的语句,我假设它是这个:

    var binarySearchTree = new BinarySearchTree(5);
    
  • 当执行breadthFirst 时,此binarySearchTree 将成为this 对象。 this 的值在循环过程中不会改变,所以循环会一直推送相同的this.leftthis.right 节点

  • 虽然pop()在队列中被调用,但它的返回值被忽略了,但这正是你需要处理的。

  • 队列用节点初始化,但队列应该有节点,而不是节点值。否则,您将永远无法检索节点的子节点。

  • 驱动程序代码中的最后一个console.log 不会打印任何有用的信息,因为breadthFirst 方法并非旨在返回任何内容。相反,它通过回调提供结果。所以这个console.log是没用的。

  • 由于驱动程序代码中的回调将值收集到一个数组中,因此您可能希望在树遍历完成后打印该数组。

更正

这是解决了这些问题的脚本:

function BinarySearchTree(value) {
  this.value = value;
  this.right = null;
  this.left = null;
}

BinarySearchTree.prototype.add = function(value) {
  if (value < this.value) {
    if (this.left) this.left.add(value);
    else this.left = new BinarySearchTree(value);
  }

  if (value > this.value){
    if (this.right) this.right.add(value);
    else this.right = new BinarySearchTree(value);
  }
};

BinarySearchTree.prototype.breadthFirst = function(callback) {
  let queue = [];
  queue.push(this); // Don't push the value, push the root node
  while (queue.length) {
    let node = queue.pop(); // Pop returns the node: capture it!
    callback(node.value); // Work with that node, not with `this`
    if (node.left) queue.push(node.left);
    if (node.right) queue.push(node.right);
  }
};

var array = [];
var func = function(value){ array.push(value); };
var binarySearchTree = new BinarySearchTree(5); // This was missing
binarySearchTree.add(2);
binarySearchTree.add(3);
binarySearchTree.add(7);
binarySearchTree.add(6);
binarySearchTree.breadthFirst(func); // Does not return anything: don't print
console.log(array); // Output what was collected: [ 5, 2, 3, 7, 6 ]

现代版

您的代码的某些方面可以使用一些更好的编程模式:

  • 没有办法用您的代码定义一个 empty 树。最好定义一个支持此状态的容器,这意味着您不必使用第一个值调用其构造函数,而是可以使用 add 方法添加 all 值。李>
  • 自 ECMAScript 2015 起,我们可以使用 class 语法
  • 不要使用回调系统,而是使用生成器

以下是这些想法和一些其他更新后的代码外观:

class Node {
    constructor(value) {
        this.value = value;
        this.right = this.left = null;
    }
}

class BinarySearchTree {
    constructor() {
        this.root = null;
    }
    add(value) {
        function recur(node, value) {
            if (!node) return new Node(value);
            if (value < node.value) {
                node.left = recur(node.left, value);
            } else if (value > node.value) {
                node.right = recur(node.right, value);
            }
            return node;
        }
        this.root = recur(this.root, value);
    }
    *breadthFirst() {
        const queue = [];
        if (this.root) queue.push(this.root);
        while (queue.length) {
            const node = queue.pop();
            yield node.value;
            if (node.left) queue.push(node.left);
            if (node.right) queue.push(node.right);
        }
    }
}

const binarySearchTree = new BinarySearchTree;
for (const value of [5, 2, 3, 7, 6]) binarySearchTree.add(value);
console.log(...binarySearchTree.breadthFirst());

【讨论】:

  • 对此答案有任何反馈吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-10
  • 1970-01-01
  • 2012-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-28
相关资源
最近更新 更多