码迷,mamicode.com
首页 > 编程语言 > 详细

怎样通过JavaScript遍历树

时间:2020-04-03 18:36:13      阅读:142      评论:0      收藏:0      [点我收藏+]

标签:垂直   适应   技术   完成   tree   mic   搜索   https   而不是   

树基本上只是花哨的链表,并且在树上创建和删除节点非常简单。另一方面,当它们未排序时,搜索会有些棘手,因此我们将研究几种不同的方式来处理整个树的搜索。

技术图片

先决条件

您将需要基本了解什么是树以及它们如何工作。我们使用Binary Search Tree的特定示例,但是与确切的实现相比,它们更多的是技术和模式,并且可以轻松地适用于任何类型的树。

概念

使用JS二叉搜索树我们可以使用相同的系统来创建一个新节点,就像找到一个一样。标准树(例如文件系统)不遵循任何特定规则,因此迫使我们通过树或子树查看每个项目以查找所需内容。这就是为什么搜索特定文件可能要花费这么长时间的原因。

没有很多方法可以优化过去,O(n)但是有两种主要的“哲学”可以搜索整个树,即通过广度优先(水平在同级之间)或深度优先(垂直在父母与孩子之间)进行搜索。

由于二叉搜索树最容易建立,因此我们可以将仅添加节点的快速树放在一起。

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

class BST {
  constructor() {
    this.root = null;
  };
  create(val) {
    const newNode = new Node(val);
    if (!this.root) {
      this.root = newNode;
      return this;
    };
    let current = this.root;

    const addSide = side => {
      if (!current[side]) {
        current[side] = newNode;
        return this;
      };
      current = current[side];
    };

    while (true) {
      if (val === current.val) return this;
      if (val < current.val) addSide(‘left‘);
      else addSide(‘right‘);
    };
  };
};

const tree = new BST();
tree.create(20);
tree.create(14);
tree.create(57);
tree.create(9);
tree.create(19);
tree.create(31);
tree.create(62);
tree.create(3);
tree.create(11);
tree.create(72);

广度优先搜索

广度优先搜索的特征在于,它着重于从左到右,在每个级别上的每个项目,然后再转移到下一个。

这包括三个主要部分:当前节点,访问的节点列表以及用于跟踪需要查看哪些节点的基本队列(我们将只使用数组,因为它将永远不会很长) 。

无论我们是什么人current,我们都会将其子级(从左到右)推入队列,因此看起来像[20, 14, 57]。然后,我们将切换current到队列中的下一个项目,并将其左,右子级添加到队列的末尾[14, 57, 9, 19]

现在,visited当我们移至下一个项目,查找其子项目并将其添加到队列中时,可以删除并添加当前项目。这将重复进行,直到我们的队列为空并且每个值都在中visited

BFS() {
  let visited = [],
      queue = [],
      current = this.root;

  queue.push(current);
  while (queue.length) {
    current = queue.shift();
    visited.push(current.val);

    if (current.left) queue.push(current.left);
    if (current.right) queue.push(current.right);
  };

    return visited;
}

console.log(tree.BFS()); //[ 20, 14, 57, 9, 19, 31, 62, 3, 11, 72 ]

深度优先搜索

深度优先搜索与完成每个级别相比,更关心的是完成从树的整个侧面到叶子的遍历。

有处理这种方式主要有三种,preOrderpostOrder,和inOrder但他们彼此只是很轻微的修改来改变输出顺序。更好的是,我们甚至不必担心队列。

从根开始,我们将使用一个简短的递归函数来记录我们的节点,然后尽可能向下移动到左边,并记录其路径。完成左侧操作后,它将开始处理剩余的右侧值,直到记录完整个树为止。最终访问应该看起来像[24, 14, 9, 3, 11, 19, ...]

preOrder() {
  let visited = [],
      current = this.root;

  let traverse = node => {
    visited.push(node.val);
    if (node.left) traverse(node.left);
    if (node.right) traverse(node.right);
  };

  traverse(current);
  return visited;
}

console.log(tree.preOrder()); // [ 20, 14, 9, 3, 11, 19, 57, 31, 62, 72 ]

您可能已经猜到了,postOrder与的相反preOrder,我们仍在垂直工作,但是我们从底部到顶部进行搜索,而不是从根到叶。

我们将从最底部的节点开始,并记录其及其兄弟节点,然后再移至其父节点。被访问的前半部分应该看起来像这样[3, 11, 9, 19, 14, ...],因为它可以使它在树上冒泡。

我们可以通过visited在两个遍历完成之后将节点推入来轻松实现此目的。

postOrder() {
  let visited = [],
      current = this.root;

  let traverse = node => {
    if (node.left) traverse(node.left);
    if (node.right) traverse(node.right);
    visited.push(node.val);
  };

  traverse(current);
  return visited;
}

console.log(tree.postOrder()); // [ 3, 11, 9, 19, 14, 31, 72, 62, 57, 20 ]

与的访问类似postOrderpreOrder访问从下而上进行,但仅在访问任何同级之前访问父项。

在遍历左侧之后,在右侧之前,我们可以推入列表,而不是开始或结束。我们的结果将如下所示[3, 9, 11, 14, 19, 20, ...]

inOrder() {
  let visited = [],
      current = this.root;

  let traverse = node => {
    if (node.left) traverse(node.left);
    visited.push(node.val);
    if (node.right) traverse(node.right);
  };

  traverse(current);
  return visited;
}

console.log(tree.inOrder()); // [ 3, 9, 11, 14, 19, 20, 31, 57, 62, 72 ]

总结思想

当然,所有这些算法都是O(n)因为要着眼于每个节点,没有太多的捷径或技巧。

请记住,这些并不是需要记住的确切实现,而是解决问题和构建更有价值的算法的通用模式。一旦您了解了下划线的概念,便可以轻松地将它们适应任何语言或框架。

怎样通过JavaScript遍历树

标签:垂直   适应   技术   完成   tree   mic   搜索   https   而不是   

原文地址:https://blog.51cto.com/14763751/2484642

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!