二叉树的锯齿形层次遍历(Zigzag Level Order Traversal)实现与解析

2025/3/15
本文详细介绍了二叉树的锯齿形层次遍历(Zigzag Level Order Traversal)的实现思路和代码实现。通过使用队列和标志位,我们可以高效地实现从左到右和从右到左交替遍历二叉树的每一层。文章还提供了JavaScript代码示例,并对代码进行了详细解释和复杂度分析。
二叉树结构图,层次遍历示意图,JavaScript代码截图

二叉树的锯齿形层次遍历(Zigzag Level Order Traversal)是一种特殊的层次遍历方式,它要求我们在遍历二叉树时,按照层次从左到右或从右到左交替进行。具体来说,第一层从左到右,第二层从右到左,第三层从左到右,以此类推。

实现思路

  1. 使用队列进行层次遍历:我们可以使用队列来实现层次遍历。首先将根节点入队,然后逐层处理队列中的节点。

  2. 使用标志位控制遍历方向:我们可以使用一个标志位(如 leftToRight)来控制当前层的遍历方向。当 leftToRighttrue 时,从左到右遍历;当 leftToRightfalse 时,从右到左遍历。

  3. 使用双端队列(Deque)或数组反转:为了在从右到左遍历时能够高效地插入节点,我们可以使用双端队列(Deque)或者在遍历完一层后对结果进行反转。

代码实现

以下是使用 JavaScript 实现的锯齿形层次遍历代码:

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

function zigzagLevelOrder(root) {
    if (!root) return [];

    const result = [];
    const queue = [root];
    let leftToRight = true;

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

        for (let i = 0; i < levelSize; i++) {
            const node = queue.shift();

            if (leftToRight) {
                currentLevel.push(node.val);
            } else {
                currentLevel.unshift(node.val);
            }

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

        result.push(currentLevel);
        leftToRight = !leftToRight;
    }

    return result;
}

// 示例用法
const root = new TreeNode(3);
root.left = new TreeNode(9);
root.right = new TreeNode(20);
root.right.left = new TreeNode(15);
root.right.right = new TreeNode(7);

console.log(zigzagLevelOrder(root));
// 输出: [[3], [20, 9], [15, 7]]

代码解释

  1. TreeNode 类:定义了二叉树的节点结构,每个节点包含 val(节点值)、left(左子节点)和 right(右子节点)。

  2. zigzagLevelOrder 函数

    • 首先检查根节点是否为空,如果为空则返回空数组。
    • 使用队列 queue 来存储当前层的节点。
    • leftToRight 标志位用于控制当前层的遍历方向。
    • 在每一层的遍历中,根据 leftToRight 的值决定是将节点值添加到 currentLevel 的开头还是末尾。
    • 遍历完一层后,将 currentLevel 添加到 result 中,并反转 leftToRight 的值。
    • 最后返回 result

复杂度分析

  • 时间复杂度:O(N),其中 N 是二叉树的节点数。每个节点都会被访问一次。
  • 空间复杂度:O(M),其中 M 是二叉树的最大宽度(即某一层的最大节点数)。在最坏情况下,队列中会存储一层的所有节点。

总结

锯齿形层次遍历是一种常见的二叉树遍历方式,通过使用队列和标志位,我们可以高效地实现这一遍历方式。在实际应用中,这种遍历方式可以用于解决一些特定的问题,如按层打印二叉树、计算每层的最大值等。

上次更新:

相关文章

npx完全指南:前端开发必备工具详解 | 20年架构师深度解析

本文由20年前端架构师深入解析npx工具,涵盖其核心功能、优势、高级用法、最佳实践及与npm/yarn的区别比较,帮助开发者掌握这一现代前端开发利器。

·前端开发

Astro 静态站点生成器:构建高性能网站的最佳选择

Astro 是一个专注于构建快速、轻量级网站的静态站点生成器,支持多种前端框架,采用岛屿架构减少 JavaScript 加载,提升性能。

·前端开发

MySQL JSON数据类型支持与使用指南 | 详细解析与示例

本文详细解析了MySQL从5.7版本开始支持的JSON数据类型,包括版本支持、创建JSON字段、插入与查询JSON数据、修改JSON数据、生成JSON、索引优化、性能与应用场景、注意事项及示例全流程。

·后端开发

Weex 跨平台移动开发框架:核心特性与使用指南

Weex 是由阿里巴巴开源的跨平台移动开发框架,支持使用 Vue.js 或 Rax 构建高性能的 iOS、Android 和 Web 应用。本文详细解析了 Weex 的核心特性、架构、工作流程、组件和模块、开发工具、优缺点、应用场景及未来发展。

·前端开发

ECharts 与 DataV 数据可视化工具对比分析 | 选择指南

本文详细对比了 ECharts 和 DataV 两个常用的数据可视化工具,包括它们的设计目标、优缺点、使用场景和技术栈,帮助读者根据具体需求选择合适的工具。

·前端开发

前端部署后通知用户刷新页面的常见方案 | 单页应用更新提示

本文介绍了在前端部署后通知用户刷新页面的几种常见方案,包括WebSocket实时通知、轮询检查版本、Service Worker版本控制、版本号对比、自动刷新、使用框架内置功能以及第三方库。每种方案的优缺点和示例代码均有详细说明。

·前端开发

TypeScript 映射类型常见问题与解决方案 | 提升代码维护性

本文探讨了在使用 TypeScript 时,映射类型的不当使用可能导致的问题,如代码难以维护、类型推断不准确或性能问题,并提供了相应的解决方案和最佳实践。

·编程语言

TypeScript 交叉类型与联合类型:区别与最佳实践

本文详细解释了 TypeScript 中交叉类型(Intersection Types)和联合类型(Union Types)的区别,提供了使用场景、类型守卫、避免过度使用交叉类型的建议,以及如何通过工具辅助解决混淆问题。

·编程语言

TypeScript 类继承中的常见类型问题及解决方案 | TypeScript 开发指南

本文详细探讨了在 TypeScript 中使用类继承时可能遇到的常见类型问题,包括类型兼容性、构造函数、方法重写、访问修饰符、泛型类继承、抽象类以及类型断言等问题,并提供了相应的解决方案和代码示例。

·编程语言

TypeScript 函数重载:常见问题与解决方案

本文探讨了 TypeScript 中函数重载的常见问题,包括签名与实际实现不匹配、重载签名过多、与泛型结合时的类型推断问题等,并提供了相应的解决方案。

·编程语言