• 一种分层数据的抽象模型
  • 前端工作中常见的树包括:DOM树、级联选择、树形控件
  • JS没有树,但可以用Object和Array构建树
  • 树的常见操作:深度/广度优先遍历、先中后序遍历

深度/广度遍历

深度优先遍历

  • 概念:尽可能深的搜索树的分支

image.png

  • 深度优先遍历的 算法口诀

    • 访问根节点
    • 对根节点的children 挨个进行深度优先遍历

      广度优先遍历

  • 概念:先访问离根节点最近的节点

image.png

  • 广度优先遍历的 算法口诀
    • 1.新建一个队列,把根节点入队
    • 2.把队头出队,并访问
    • 3.把对头的children挨个入队
    • 4.重复第二、第三步,直到队列为空

二叉树

  • 二叉树:树中每个节点最多只能由两个子节点
    • 在JS中,常用Object来模拟二叉树

image.png

  1. const bt = {
  2. val: 1,
  3. left: {
  4. val: 2,
  5. left: {
  6. val: 4,
  7. left: null,
  8. right: null,
  9. },
  10. right: {
  11. val: 5,
  12. left: null,
  13. right: null,
  14. }
  15. },
  16. right: {
  17. val: 3,
  18. left: {
  19. val: 6,
  20. left: null,
  21. right: null
  22. },
  23. right: {
  24. val: 7,
  25. left: null,
  26. right: null
  27. }
  28. }
  29. }
  30. module.exports = bt;

先序遍历

递归版

  • 先序遍历的算法口诀
    • 访问根节点
    • 对根节点的子树进行先序遍历
    • 对根节点的子树进行先序遍历

image.png

  • 对这个树:1—>2—>3—>4—>5—>6—>7

    1. const preOrder = (root) => {
    2. if(!root) return;
    3. console.log(root.val);
    4. preOrder(root.left);
    5. preOrder(root.right);
    6. }

    非递归版

    1. const preOrder = (root) => {
    2. if (!root) return;
    3. const stack = [root]; // 用栈模仿递归的栈
    4. while (stack.length) {
    5. const node = stack.pop();
    6. console.log(node.val);
    7. if (node.right) stack.push(node.right);
    8. if (node.left) stack.push(node.left);
    9. }
    10. }

    中序遍历

    递归版

  • 中序遍历的算法口诀

    • 对根节点的子树进行中序遍历
    • 访问根节点
    • 对根节点的子树进行中序遍历

image.png

  • 对这个树:1—>2—>3—>4—>5—>6—>7
    1. const inOrder = (root) => {
    2. if (!root) return;
    3. inOrder(root.left);
    4. console.log(root.val);
    5. inOrder(root.right);
    6. }

    非递归版

    ```javascript const inOrder = (root) => { if (!root) return; const stack = []; let p = root; // 声明一个指针 while (stack.length || p) { while (p) {
    1. stack.push(p);
    2. p = p.left;
    } const node = stack.pop(); console.log(node.val); p = node.right; }

}

  1. <a name="WpzKa"></a>
  2. ## 后序遍历
  3. <a name="KbN4Q"></a>
  4. ### 递归版
  5. - 后序遍历的算法口诀
  6. - 对根节点的**左**子树进行后序遍历
  7. - 对根节点的**右**子树进行后序遍历
  8. - 访问根节点
  9. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1174243/1628826838258-11b23a4a-b6ba-43bd-8ad2-ca1124db86c3.png#clientId=uafeef4ad-9357-4&from=paste&height=193&id=u23d611ab&margin=%5Bobject%20Object%5D&name=image.png&originHeight=386&originWidth=384&originalType=binary&ratio=1&size=60448&status=done&style=none&taskId=ub998ee29-5196-4eee-b1f2-88a47dc57dd&width=192)
  10. - 对这个树:1—>2—>3—>4—>5—>6—>7
  11. ```javascript
  12. const postOrder = (root) => {
  13. if(!root) return;
  14. postOrder(root.left);
  15. postOrder(root.right);
  16. console.log(root.val);
  17. }

非递归版

const postOrder = (root) => {
  if (!root) return;
  const stack = [root];
  const outputStack = [];
  while (stack.length) {
    const node = stack.pop();
    outputStack.push(node);
    if (node.left) stack.push(node.left);
    if (node.right) stack.push(node.right);
  }
  while(outputStack.length) {
    const node = outputStack.pop();
    console.log(node.val);
  }
}