109 阅读2分钟

一、树的基础概念

树是一种分层结构的非线性数据结构,像家谱、公司组织架构、文件目录都是树状结构。 一个“树”至少有一个节点,这个节点叫做根节点(root),其下可以有很多子节点(children),每个子节点又可能有自己的子节点…

树的术语

名称说明
根节点树的最上面那个节点
子节点根节点的子分支节点
叶子节点没有子节点的节点
父节点某个子节点的上一级节点
深度从根节点到该节点的路径长度
高度从该节点到叶子节点最长路径长度

二、二叉树(Binary Tree)

什么是二叉树?

每个节点最多有两个子节点(左子树、右子树),就是二叉树。

     1
    / \
   2   3
  / \
 4   5

JS 中二叉树结构(基础写法):

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

三、二叉搜索树(BST)

什么是 BST?

二叉搜索树是一种特殊的二叉树,满足:

  • 左子树所有节点 < 根节点
  • 右子树所有节点 > 根节点
  • 每棵子树也都是 BST
      5
     / \
    3   7
   / \   \
  2   4   9

四、遍历方式

按顺序访问每个节点

遍历二叉树分为:

1、前序遍历(根→左→右)

function preOrder(root) {
  if (!root) return;

  console.log(root.value);
  preOrder(root.left);
  preOrder(root.right);
}

2、中序遍历(左→根→右)

function inOrder(root) {
  if (!root) return;

  inOrder(root.left);
  console.log(root.value);
  inOrder(root.right);
}

3、后序遍历(左→右→根)

function postOrder(root) {
  if (!root) return;

  postOrder(root.left);
  postOrder(root.right);
  console.log(root.value);
}

4、层序遍历(Level Order Traversal)函数,也叫广度优先遍历,(从上到下,从左到右)➡️ 借助队列

function levelOrder(node) {
    if(!root) return;

    const queue = [root];
    while(queue.length) {
        const node = queue.shift();
        console.log(node.value);
        if(node.left) queue.push(left);
        if(node.right) queue.push(right);
    }
}

五、经典二叉树题目(LeetCode高频)

1. 最大深度(递归)

function maxDepth(root) {
  if (!root) return 0;

  return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
}

2. 路径总和(是否存在一条路径从根到叶子,和为 target)

function hasSumPath(root, target) {
  if (!root) return false;
  if (!root.left && !root.right) return root.val === target;

  return (
    hasSumPath(root.left, target - root.val) ||
    hasSumPath(root.right, target - root.val)
  );
}

3. 平衡二叉树(左右子树高度差不超过 1)

一棵二叉树是“平衡的”,指的是:

对于每个节点,它的左子树和右子树的高度差不超过 1,并且左右子树本身也是平衡的。

平衡的例子 ✅:

       1
      / \
     2   3
    /
   4

每一层的计算如下:

  • 节点 4:左右都是 null,高度为 0 → 返回 1
  • 节点 2:左边是 1,右边是 0,差值 1 → 返回 2
  • 节点 3:左右都是 null → 返回 1
  • 节点 1:左是 2,右是 1,差值 1 → 返回 3

最终返回 ≠ -1,所以是平衡

不平衡的例子 ❌:

       1
      /
     2
    /
   3
  • 节点 3:返回 1
  • 节点 2:左边是 1,右边是 0 → 高度 2
  • 节点 1:左边是 2,右边是 0 → 差值 2 ❌ → 返回 -1

所以最终 height(root) === -1,函数返回 false,代表不平衡。

代码如下:

function isBalanced(root) {
  function height(node) {
    if (!node) return 0;

    const left = height(node.left);
    const right = height(node.right);

    if (left === -1 || right === -1 || Math.abs(left - right) > 1) return -1;

    return Math.max(left, right) + 1;
  }

  return height(root) !== -1;
}