代码随想录算法训练营day13 | 递归遍历、迭代遍历、统一迭代、层序遍历

二叉树节点定义

点击查看代码
/**
 * 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) {}
 * };
 */

递归遍历
144. 二叉树的前序遍历(递归)

点击查看代码
class Solution {
public:
    void Traversal(TreeNode* root, vector<int> &v) {
        if(root == nullptr) return;
        v.push_back(root->val);  //根
        Traversal(root->left, v);  //左
        Traversal(root->right, v);  //右
    }
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        Traversal(root, result);
        return result;
    }
};

94.二叉树的中序遍历(递归)

点击查看代码
class Solution {
public:
    void Traversal(TreeNode* root, vector<int> &v) {
        if(root == nullptr) return;
        Traversal(root->left, v);  //左
        v.push_back(root->val);  //根
        Traversal(root->right, v);  //右
    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        Traversal(root, result);
        return result;
    }
};

145.二叉树的后序遍历(递归)

点击查看代码
class Solution {
public:
    void Traversal(TreeNode* root, vector<int> &v) {
        if(root == nullptr) return;
        Traversal(root->left, v);  //左
        Traversal(root->right, v);  //右
        v.push_back(root->val);  //根
    }
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        Traversal(root, result);
        return result;
    }
};

迭代遍历
144.二叉树的前序遍历(迭代)

点击查看代码
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        if(root == nullptr) return result;
        //注意栈里存放的是节点的指针
        stack<TreeNode*> stk;
        stk.push(root);
        while(!stk.empty()) {
            TreeNode *rootEle = stk.top();
            stk.pop();
            result.push_back(rootEle->val);  //根
            //注意是右孩子先入栈,因为先入栈的后处理
            if(rootEle->right) //注意,迭代写法访问左右时要写if判断,因为不会通过递归终止判断,空指针不入栈
                stk.push(rootEle->right);  //左
            if(rootEle->left)
                stk.push(rootEle->left);  //右
        }
        return result;
    }
};

145.二叉树的后序遍历(迭代)

点击查看代码
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        if(root == nullptr) return result;
        //注意栈里存放的是节点的指针
        stack<TreeNode*> stk;
        stk.push(root);
        while(!stk.empty()) {
            TreeNode *rootEle = stk.top();
            stk.pop();
            result.push_back(rootEle->val);
            if(rootEle->left) //注意,迭代写法访问左右时要写if判断,因为不会通过递归终止判断,空指针不入栈
                stk.push(rootEle->left);
            if(rootEle->right)
                stk.push(rootEle->right);
        }
        reverse(result.begin(), result.end());
        return result;
    }
};

迭代法的后序遍历由迭代法的先序遍历稍微修改即可
因为先序是根左右,将其改为根右左,最后再将result数组reverse就成为左右根,刚好为后序
根右左,右先处理,故后入栈,先入栈左孩子

94.二叉树的中序遍历(迭代)
中序遍历的迭代法比较特殊,先跳过...

统一迭代
掌握前序和后序的迭代法即可,中序迭代比较特殊,先跳过,统一迭代先跳过...

层序遍历
层序遍历处理每个节点时,需要将其pop出队列后将其所有孩子都push进队列,才算处理完成
以下所有题目均使用102题层序遍历模板稍作修改即可
102.二叉树的层序遍历

点击查看代码
<details>
<summary>点击查看代码</summary>

class Solution {
public:
vector<vector> levelOrder(TreeNode* root) {
vector<vector> result;
if(root == nullptr) return result;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()) {
int size = que.size(); //核心语句,记录每层的节点个数
vector curResult;
while(size-- > 0) {
TreeNode *cur = que.front();
que.pop();
curResult.push_back(cur->val);
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
result.push_back(curResult);
}
return result;
}
};

</details>
本题有一个关键点在于,如何记住每一层的节点个数,使节点为一层一层地push入二维数组中,即将一整层节点作为一个数组push进result数组中

107.二叉树的层序遍历Ⅱ

点击查看代码
/**
 * 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>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> result;
        if(root == nullptr) return result;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()) {
            int size = que.size(); //核心语句,记录每层的节点个数
            vector<int> curResult;
            while(size-- > 0) {
                TreeNode *cur = que.front();
                que.pop();
                curResult.push_back(cur->val);
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }
            result.push_back(curResult);
        }
        reverse(result.begin(), result.end()); //正常从上至下层序遍历,最后reverse一下result数组即可得到从下至上层序遍历的结果
        return result;        
    }
};

199.二叉树的右视图

点击查看代码
class Solution {
public:
    vector<int> rightSideView(TreeNode* root) {
        vector<int> result;
        if(root == nullptr) return result;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()) {
            int size = que.size(); //核心语句,记录每层的节点个数
            bool flag = 1; //flag为1表示为当前行最右边的元素
            while(size-- > 0) {
                TreeNode *cur = que.front();
                que.pop();
                if(flag == 1) {
                    result.push_back(cur->val);
                    flag = 0; //关闭,当前行的后续元素不再push进结果数组
                }
                if(cur->right) que.push(cur->right);
                if(cur->left) que.push(cur->left);
            }
        }
        return result;
    }
};

本题关键点在于采用flag标志来表示当前元素是否为当前行的最右边的元素

637.二叉树的层平均值

点击查看代码
class Solution {
public:
    vector<double> averageOfLevels(TreeNode* root) {
        vector<double> result;
        if(root == nullptr) return result;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()) {
            int size = que.size(); //核心语句,记录每层的节点个数
            int len = size; //用于最后的除法求平均
            double sum = 0; //特别注意sum值需要为double型,因为结果数组为vector<double>
            while(size-- > 0) {
                TreeNode *cur = que.front();
                que.pop();
                sum += cur->val;
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }
            result.push_back(sum / len);
        }
        return result;
    }
};

429.N叉树的层序遍历
注意本题的节点定义,由于有多个孩子,故不使用左右指针,而使用指针数组表示孩子

点击查看代码
class Solution {
public:
    vector<vector<int>> levelOrder(Node* root) {
        vector<vector<int>> result;
        if(root == nullptr) return result;
        queue<Node*> que;
        que.push(root);
        while(!que.empty()) {
            int size = que.size(); //核心语句,记录每层的节点个数
            vector<int> curResult;
            while(size-- > 0) {
                Node *cur = que.front();
                que.pop();
                curResult.push_back(cur->val);
                for(int i = 0; i < cur->children.size(); ++i) 
                    que.push(cur->children[i]);
            }
            result.push_back(curResult);
        }
        return result;
    }
};

515.在每个树行中找最大值

点击查看代码
class Solution {
public:
    vector<int> largestValues(TreeNode* root) {
        vector<int> result;
        if(root == nullptr) return result;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()) {
            int size = que.size(); //核心语句,记录每层的节点个数
            int maxNum = INT_MIN;  //INT_MIN INT_MAX常量位于<climits>中
            while(size-- > 0) {
                TreeNode *cur = que.front();
                que.pop();
                maxNum = max(maxNum, cur->val);
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }
            result.push_back(maxNum);
        }
        return result;
    }
};

116.填充每个节点的下一个右侧节点指针

点击查看代码
class Solution {
public:
    Node* connect(Node* root) {
        if(root == nullptr) return root;
        queue<Node*> que;
        que.push(root);
        while(!que.empty()) {
            int size = que.size(); //核心语句,记录每层的节点个数
            Node *pre = nullptr;
            while(size-- > 0) {
                Node *cur = que.front();
                que.pop();
                //处理每个节点的逻辑是让前一个节点指向当前节点,而不处理当前节点的next指针
                if(pre != nullptr) {  //若不是当前行第一个元素,则令前一个元素指向当前元素,并更新pre指针
                    pre->next = cur;
                    pre = cur;
                }
                else {
                    pre = cur;  //若是当前行第一个元素,则令pre指向当前元素
                }
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }
            //由于初始状态下,所有next指针均为nullptr,故每行最后一个元素无需再处理
        }
        return root;        
    }
};

117.填充每个节点的下一个右侧节点指针II
完全同116,和是不是满二叉树没有半毛钱关系

点击查看代码
class Solution {
public:
    Node* connect(Node* root) {
        if(root == nullptr) return root;
        queue<Node*> que;
        que.push(root);
        while(!que.empty()) {
            int size = que.size(); //核心语句,记录每层的节点个数
            Node *pre = nullptr;
            while(size-- > 0) {
                Node *cur = que.front();
                que.pop();
                //处理每个节点的逻辑是让前一个节点指向当前节点,而不处理当前节点的next指针
                if(pre != nullptr) {  //若不是当前行第一个元素,则令前一个元素指向当前元素,并更新pre指针
                    pre->next = cur;
                    pre = cur;
                }
                else {
                    pre = cur;  //若是当前行第一个元素,则令pre指向当前元素
                }
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }
            //由于初始状态下,所有next指针均为nullptr,故每行最后一个元素无需再处理
        }
        return root; 
    }
};

104.二叉树的最大深度(层序遍历)

点击查看代码
class Solution {
public:
    int maxDepth(TreeNode* root) {
        int depth = 0;
        if(root == nullptr) return depth;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()) {
            ++depth; //处理新的一层
            int size = que.size(); //核心语句,记录每层的节点个数
            while(size-- > 0) {
                TreeNode *cur = que.front();
                que.pop();
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }
        }
        return depth;
    }
};

111.二叉树的最小深度(层序遍历)
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
核心是要使用层序遍历找到第一个叶子节点,找到后直接返回其所在层数

点击查看代码
class Solution {
public:
    int minDepth(TreeNode* root) {
        int depth = 0;
        if(root == nullptr) return depth;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()) {
            ++depth; //处理新的一层
            int size = que.size(); //核心语句,记录每层的节点个数
            while(size-- > 0) {
                TreeNode *cur = que.front();
                que.pop();
                //核心就是找第一个叶节点,找到后直接返回其深度,同时,求最小深度题仅比求最大深度题多了以下一行代码
                if(cur->left == nullptr && cur->right == nullptr) return depth;
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }
        }
        return depth;
    }
};

2025/02/26

posted @   coder小杰  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示