Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ajax/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 无法理解此回调函数的作用(BFS,树的宽度级别)_Javascript_Algorithm_Callback_Tree_Breadth First Search - Fatal编程技术网

Javascript 无法理解此回调函数的作用(BFS,树的宽度级别)

Javascript 无法理解此回调函数的作用(BFS,树的宽度级别),javascript,algorithm,callback,tree,breadth-first-search,Javascript,Algorithm,Callback,Tree,Breadth First Search,我目前正在研究和学习树,并一直在处理不同的遍历实现 class Node { constructor(data) { this.data = data; this.children = []; } add(data) { this.children.push(new Node(data)); } remove(data) { this.children = this.children.filter(node => {

我目前正在研究和学习树,并一直在处理不同的遍历实现

class Node {
  constructor(data) {
      this.data = data;
      this.children = [];
  }

  add(data) {
      this.children.push(new Node(data));
  }

  remove(data) {
      this.children = this.children.filter(node => {
          return node.data !== data;
      })
  }
}

traverseBF(fn) {
    const arr = [this.root];
    while (arr.length) {
        const node = arr.shift();
        arr.push(...node.children);
        fn(node); //what role does this play?
    }
    return count;
}

traverseDF(fn) {
    const arr = [this.root]; 
    while (arr.length) {  
        const node = arr.shift(); 
        arr.unshift(...node.children); 
        fn(node); //what role does this play???
    }
}
我想我已经理解了回调具有声明它的上下文,并且能够访问外部函数中的变量,我认为是arr保持最新的原因,回调函数对于BFS/DFS在这个实例中的工作是不可或缺的。然而,学习计算宽度水平打破了我的理解

function levelWidth(root) {
  const arr = [root, 's'];
  const counters = [0];

  while (arr.length > 1) {
      const node = arr.shift();

      if (node === 's') {
          counters.push(0);
          arr.push('s');
      } else {
          arr.push(...node.children);
          counters[counters.length - 1]++;
      }
  }
  return counters;
}
这里还没有回调,这个BFS搜索和遍历工作正常。有谁能帮我更好地理解为什么一开始就需要它,而不是这次

当我这样调用遍历时,到底发生了什么

const letters = [];
const t = new Tree();
t.root = new Node('a');
t.root.add('b');
t.root.add('d');
t.root.children[0].add('c');
t.root.children[1].add('e');

t.traverseBF(node => {
    letters.push(node.data);
});
console.log(letters);

这里没有对错

回调版本有两种不同:

  • 它不使用访问的节点应用任何逻辑。它只负责遍历,不负责任何其他逻辑。任何特定的逻辑都留给调用方,调用方可以为此目的传递回调。在最后一个示例中,该特定逻辑包括将节点的
    数据
    值收集到一个数组中。但是请注意,遍历函数不知道这个逻辑,这是一个很好的关注分离

    注意:
    transversebf(fn)
    末尾的
    返回计数
    不应该存在(没有
    计数

  • 它不会让调用方一直等待,直到访问了所有节点

非回调版本不仅访问节点,还负责这些节点上的特定处理(即一些计数),并且只返回该处理的结果。这是不太通用的。如果您想为完全不同的目的进行遍历,则不能使用此函数,因为它实际上不会告诉调用方它访问过的节点,也不会告诉调用方发生这种情况的顺序

您还可以想象一种“中间”遍历实现:不使用回调,只收集数组中所有已访问的节点,然后按访问顺序返回完整的节点数组。这更一般,但调用方必须等到访问了所有节点后,才能开始对返回的节点数组应用自己的算法

因此,我认为回调版本更灵活、更通用

然而,实现这种通用遍历的更现代的方法不是通过回调系统,而是作为生成器

下面是它的外观(注意首字母
*


这里的另一个优点是调用方总是可以决定停止遍历。在上面的代码中,循环的早期中断实际上意味着遍历将不再完成。对于前面提到的所有其他方法,您必须触发一个异常以使其成为可能;在所有其他情况下,遍历必须运行到完成。

谢谢,这非常有帮助。
* traverseBF() {
    const arr = [this.root];
    while (arr.length) {
        const node = arr.shift();
        arr.push(...node.children);
        yield node;  // <---
    }
}

* traverseDF() {
    const arr = [this.root]; 
    while (arr.length) {  
        const node = arr.shift(); 
        arr.unshift(...node.children); 
        yield node; // <---
    }
}
let letters = [];
for (let node of t.traverseDF()) {
    // do something with this node before continuing the traversal
    letters.push(node.data);
}
console.log(letters);