LeetCode Day15

92 阅读4分钟

二叉树层序遍历

一般思路

层序遍历(Level-order Traversal)通常用于遍历树或图的数据结构。对于二叉树,这意味着按照从上到下、从左到右的顺序访问每个节点。以下是解决这类问题时的一般思考过程:

1. 选择数据结构

由于层序遍历需要先访问当前层的所有节点,然后再访问下一层的所有节点,因此队列是一个合适的数据结构。队列能够确保节点以先进先出(FIFO)的方式被处理。

2. 初始化

  • 创建一个空的结果数组(通常是一个二维数组)。
  • 创建一个队列,并将根节点加入队列。

3. 主循环

进行主循环,直到队列为空:

  • 获取当前队列的大小(这就是当前层的节点数量)。
  • 创建一个新的数组(或向量),用于存储当前层的节点值。
  • 循环处理当前层的每个节点:出队,访问其值,并将其子节点(如果有)加入队列。
  • 将当前层的节点值数组添加到结果数组中。

4. 返回结果

返回结果数组。

以上就是解决层序遍历问题时的一般思考过程。这个过程不仅适用于基础的层序遍历,还可以轻微地调整以解决更复杂的问题,如之字形遍历、每层节点的平均值等。

通过一道例题来理解

102.二叉树的层序遍历

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

在这里我们使用迭代的写法

思路 1:初始化数据结构

首先,我们需要一个队列来存储待访问的节点。我们也需要一个二维数组来存储结果。

queue<TreeNode*> q;
vector<vector<int>> result;

思路 2:处理根节点

如果根节点不为空,我们将其加入队列。

if (root != nullptr) {
    q.push(root);
}

思路 3:开始主循环

现在我们进入一个循环,该循环将持续到队列为空。在每一次迭代中,我们都会处理当前层的所有节点。

while (!q.empty()) {
    // 这里会添加处理当前层节点的代码
}

思路 4:获取当前层的节点数

在主循环的每一次迭代中,首先获取当前层的节点数,这就是队列的当前大小。

int levelSize = q.size();

思路 5:遍历当前层的所有节点

接下来,我们创建一个新的向量 currentLevel,并遍历当前层的所有节点。我们将每个节点从队列中移除,并将其值添加到 currentLevel 向量中。同时,我们将该节点的非空子节点加入队列。

vector<int> currentLevel;
for (int i = 0; i < levelSize; ++i) {
    TreeNode* currentNode = q.front();
    q.pop();
    currentLevel.push_back(currentNode->val);

    if (currentNode->left != nullptr) {
        q.push(currentNode->left);
    }
    if (currentNode->right != nullptr) {
        q.push(currentNode->right);
    }
}

思路 6:保存当前层的结果

最后,我们将 currentLevel 向量添加到 result 二维向量中。

result.push_back(currentLevel);

这样,当主循环结束时,result 二维向量就会包含层序遍历的结果。

将所有这些思路组合在一起,就形成了完整的解决方案。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    // 主函数,用于进行层序遍历并返回结果
    vector<vector<int>> levelOrder(TreeNode* root) {
        // result 用于存储最终的层序遍历结果
        vector<vector<int>> result;

        // 如果根节点为空,直接返回空结果
        if (root == nullptr) {
            return result;
        }

        // 初始化队列 q,并将根节点加入队列
        queue<TreeNode*> q;
        q.push(root);

        // 主循环,当队列不为空时执行
        while (!q.empty()) {
            // 获取当前层的节点数量(即队列的大小)
            int levelSize = q.size();

            // 初始化一个向量,用于存储当前层的节点值
            vector<int> currentLevel;

            // 遍历当前层的所有节点
            for (int i = 0; i < levelSize; ++i) {
                // 出队一个节点,并获取其值
                TreeNode* currentNode = q.front();
                q.pop();
                currentLevel.push_back(currentNode->val);

                // 如果该节点有左子节点,将其加入队列
                if (currentNode->left != nullptr) {
                    q.push(currentNode->left);
                }
                // 如果该节点有右子节点,将其加入队列
                if (currentNode->right != nullptr) {
                    q.push(currentNode->right);
                }
            }

            // 将当前层的结果添加到最终结果中
            result.push_back(currentLevel);
        }

        // 返回最终的层序遍历结果
        return result;
    }
};