力扣 103 题:二叉树的锯齿形层序遍历


力扣 103 题:二叉树的锯齿形层序遍历 C 语言实现详解

题目描述

给定一个二叉树,返回其节点值的锯齿形层序遍历。(即先从左往右,再从右往左交替进行)。

例如:

给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回锯齿形层序遍历为:
[
  [3],
  [20,9],
  [15,7]
]

解决思路

  1. 层序遍历:本题可以看作普通层序遍历的变种,但需要在每一层节点遍历时决定输出方向。
  2. 锯齿形控制
    • 当层号为偶数时,从左到右存储节点。
    • 当层号为奇数时,从右到左存储节点。
  3. 数据结构
    • 使用队列保存树节点进行层序遍历。
    • 使用一个动态数组存储结果。

C 语言实现

核心代码

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

// 定义树节点结构体
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
};

// 定义队列节点结构体
struct QueueNode {
    struct TreeNode *node;
    struct QueueNode *next;
};

// 定义队列操作
void enqueue(struct QueueNode **front, struct QueueNode **rear, struct TreeNode *node) {
    struct QueueNode *newNode = (struct QueueNode *)malloc(sizeof(struct QueueNode));
    newNode->node = node;
    newNode->next = NULL;
    if (*rear == NULL) {
        *front = *rear = newNode;
    } else {
        (*rear)->next = newNode;
        *rear = newNode;
    }
}

struct TreeNode* dequeue(struct QueueNode **front, struct QueueNode **rear) {
    if (*front == NULL) return NULL;

    struct QueueNode *temp = *front;
    struct TreeNode *node = temp->node;

    *front = (*front)->next;
    if (*front == NULL) *rear = NULL;

    free(temp);
    return node;
}

// 锯齿形层序遍历
int** zigzagLevelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes) {
    *returnSize = 0;
    if (root == NULL) return NULL;

    int **result = (int **)malloc(sizeof(int *) * 1000); // 预分配最大1000层
    *returnColumnSizes = (int *)malloc(sizeof(int) * 1000);

    struct QueueNode *front = NULL, *rear = NULL;
    enqueue(&front, &rear, root);

    bool leftToRight = true; // 控制遍历方向

    while (front != NULL) {
        int levelSize = 0;
        struct QueueNode *temp = front;

        // 统计当前层的节点数
        while (temp != NULL) {
            levelSize++;
            temp = temp->next;
        }

        result[*returnSize] = (int *)malloc(sizeof(int) * levelSize);
        (*returnColumnSizes)[*returnSize] = levelSize;

        int *tempResult = (int *)malloc(sizeof(int) * levelSize);
        int index = 0;

        // 遍历当前层
        for (int i = 0; i < levelSize; i++) {
            struct TreeNode *current = dequeue(&front, &rear);
            tempResult[index++] = current->val;

            if (current->left != NULL) {
                enqueue(&front, &rear, current->left);
            }
            if (current->right != NULL) {
                enqueue(&front, &rear, current->right);
            }
        }

        // 根据方向保存到结果
        if (leftToRight) {
            for (int i = 0; i < levelSize; i++) {
                result[*returnSize][i] = tempResult[i];
            }
        } else {
            for (int i = 0; i < levelSize; i++) {
                result[*returnSize][i] = tempResult[levelSize - i - 1];
            }
        }

        free(tempResult); // 释放临时结果
        leftToRight = !leftToRight; // 方向交替
        (*returnSize)++;
    }

    return result;
}

主函数测试代码

int main() {
    struct TreeNode node7 = {7, NULL, NULL};
    struct TreeNode node15 = {15, NULL, NULL};
    struct TreeNode node20 = {20, &node15, &node7};
    struct TreeNode node9 = {9, NULL, NULL};
    struct TreeNode root = {3, &node9, &node20};

    int returnSize = 0;
    int *returnColumnSizes = NULL;

    int **result = zigzagLevelOrder(&root, &returnSize, &returnColumnSizes);

    printf("锯齿形层序遍历结果:\n");
    for (int i = 0; i < returnSize; i++) {
        for (int j = 0; j < returnColumnSizes[i]; j++) {
            printf("%d ", result[i][j]);
        }
        printf("\n");
        free(result[i]); // 释放每一层的内存
    }
    free(result); // 释放结果数组
    free(returnColumnSizes); // 释放列大小数组

    return 0;
}

核心递归逻辑解释

1. 层序遍历实现

  • 使用队列实现层序遍历。
  • 每次从队列中取出当前层的所有节点。

2. 锯齿形实现

  • 利用 leftToRight 标志位控制当前层节点存储顺序。
  • 偶数层:从左到右存储;
  • 奇数层:从右到左存储(即逆序存储)。

3. 动态数组存储

  • 使用动态分配的二维数组存储每层的结果,避免固定数组长度的问题。

总结

  1. 本题核心是层序遍历和方向控制的结合。
  2. zigzagLevelOrder 函数通过队列实现遍历,并动态调整输出方向。
  3. 在实现中需要特别注意内存分配和释放,避免内存泄漏。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值