LeetCode体操-11 | 144. 二叉树的前序遍历、145. 二叉树的后序遍历、94. 二叉树的中序遍历、102.二叉树的层序遍历

67 阅读5分钟

理论知识

树是一种非线性的数据结构,它由节点(或顶点)和边组成。树具有以下特点:

  • 有一个特殊的节点称为根节点
  • 除根节点外,每个节点都有且只有一个父节点
  • 每个节点可以有零个或多个子节点
  • 没有子节点的节点称为叶子节点

相关术语:

  • 根节点:树的顶端节点。
  • 子节点:由一个节点直接连接的下一级节点。
  • 父节点:直接连接其子节点的上一级节点。
  • 叶节点:没有子节点的节点。
  • 深度:从根节点到某节点的路径长度。
  • 高度:从某节点到叶节点的最长路径长度。
  • 层次:树中节点的层次关系,从根节点开始计数,根节点为第0层。

树的种类

  • 二叉树:每个节点最多有两个子节点。
  • 平衡树:任意节点的两个子树的高度差不超过1。
  • 搜索树:每个节点的左子节点值小于该节点值,右子节点值大于该节点值。
  • 红黑树:一种自平衡二叉搜索树,确保树的高度维持在O(log n)。

树的遍历方式

  • 前序遍历:根节点 -> 左子树 -> 右子树
  • 中序遍历:左子树 -> 根节点 -> 右子树
  • 后序遍历:左子树 -> 右子树 -> 根节点
  • 层次遍历:按层次逐层遍历,从上到下,从左到右

144. 二叉树的前序遍历

题目

解题思路

递归方法:

  1. 访问根节点
  2. 递归遍历左子树
  3. 递归遍历右子树

迭代方法(使用栈):

  1. 将根节点压入栈
  2. 当栈不为空时,弹出栈顶节点并访问
  3. 将右子节点压入栈(如果存在)
  4. 将左子节点压入栈(如果存在)
  5. 重复步骤2-4直到栈为空

代码实现

// 递归法
function preorderTraversal(root: TreeNode | null): number[] {
    function traverse(node: TreeNode | null, result: number[]) {
        if (node === null) return;
        result.push(node.val);
        traverse(node.left, result);
        traverse(node.right, result);
    }
    
    const result: number[] = [];
    traverse(root, result)
    return result;
};

// 迭代法
function preorderTraversal(root: TreeNode | null): number[] {
    if (root === null) return [];

    const result: number[] = [];
    const stack: TreeNode[] = [root];

    while (stack.length > 0) {
        const node = stack.pop()!;  // 非空断言,因为我们知道栈不为空
        result.push(node.val);

        if (node.right) stack.push(node.right);  // 先压入右子节点
        if (node.left) stack.push(node.left);    // 后压入左子节点
    }

    return result;
};

145. 二叉树的后序遍历

题目

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历

示例 1:

输入: root = [1,null,2,3]
输出: [3,2,1]

示例 2:

输入: root = []
输出: []

示例 3:

输入: root = [1]
输出: [1]

提示:

  • 树中节点的数目在范围 [0, 100] 内
  • -100 <= Node.val <= 100

解题思路

递归方法:

  1. 递归遍历左子树
  2. 递归遍历右子树
  3. 访问根节点

迭代方法(使用栈):

  1. 使用两个栈,一个用于遍历,另一个用于存储结果
  2. 将根节点压入第一个栈
  3. 当第一个栈不为空时,弹出栈顶节点并压入第二个栈
  4. 将左子节点压入第一个栈(如果存在)
  5. 将右子节点压入第一个栈(如果存在)
  6. 重复步骤3-5直到第一个栈为空
  7. 依次弹出第二个栈中的元素,即为后序遍历结果

代码实现

// 递归法
function postorderTraversal(root: TreeNode | null): number[] {
    const result: number[] = [];

    function traverse(node: TreeNode | null) {
        if (node === null) return;

        traverse(node.left);  
        traverse(node.right);
        result.push(node.val);  
    }

    traverse(root);
    return result;
};

// 迭代法
function postorderTraversal(root: TreeNode | null): number[] {
    if (root === null) return [];

    const result: number[] = [];
    const stack1: TreeNode[] = [root];
    const stack2: TreeNode[] = [];

    while (stack1.length > 0) {
        const node = stack1.pop()!;
        stack2.push(node);

        if (node.left) stack1.push(node.left);
        if (node.right) stack1.push(node.right);
    }

    while (stack2.length > 0) {
        result.push(stack2.pop()!.val);
    }

    return result;
};

94. 二叉树的中序遍历

题目

给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。

示例 1:

输入: root = [1,null,2,3]
输出: [1,3,2]

示例 2:

输入: root = []
输出: []

示例 3:

输入: root = [1]
输出: [1]

提示:

  • 树中节点数目在范围 [0, 100] 内
  • -100 <= Node.val <= 100

解题思路

递归方法:

  1. 递归遍历左子树
  2. 访问根节点
  3. 递归遍历右子树

迭代方法(使用栈):

  1. 创建一个栈和一个指针(初始指向根节点)
  2. 当指针非空或栈非空时,进行以下操作:
  3. 如果指针非空,将指针指向的节点入栈,指针移动到左子节点
  4. 如果指针为空,弹出栈顶节点并访问,指针移动到右子节点

代码实现

// 递归法
function inorderTraversal(root: TreeNode | null): number[] {
    const result: number[] = [];

    function traverse(node: TreeNode | null) {
        if (node === null) return;

        traverse(node.left);
        result.push(node.val);
        traverse(node.right);
    }

    traverse(root);
    return result;
};

// 迭代法
function inorderTraversal(root: TreeNode | null): number[] {
    const result: number[] = [];
    const stack: TreeNode[] = [];
    let current: TreeNode | null = root;

    while (current !== null || stack.length > 0) {
        while (current !== null) {
            stack.push(current);
            current = current.left;
        }
        current = stack.pop()!;
        result.push(current.val);
        current = current.right;
    }

    return result;
};

102. 二叉树的层序遍历

题目

给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。

image.png

解题思路

  1. 层序遍历是指按照树的层级,从上到下,从左到右依次访问树的所有节点。每一层的节点值要单独存储在一个数组中。可以使用队列来实现广度优先搜索
  2. 初始时将根节点入队,每次处理当前队列中的所有节点(即当前层的节点),对于每个出队的节点,将其左右子节点入队(如果存在)
  3. 重复步骤以上,直到队列为空,返回结果列表

image.png

代码实现

function levelOrder(root: TreeNode | null): number[][] {
    if(root === null) return []
    const result: number[][] = [];
    const queue: TreeNode[] = [root];

    while(queue.length > 0){
        const levelSize = queue.length;
        const currentLevel: number[] = [];

        for(let i = 0; i < levelSize; i++){
            const currentNode = queue.shift();
            if(currentNode){
                currentLevel.push(currentNode.val);
                currentNode.left && queue.push(currentNode.left);
                currentNode.right && queue.push(currentNode.right);
            }
        }
        result.push(currentLevel)
    }
    
    return result
};