代码随想录阅读笔记-二叉树【翻转二叉树】

题目

翻转一棵二叉树。

思路

如果要从整个树来看,翻转还真的挺复杂,整个树以中间分割线进行翻转,如图:

可以发现想要翻转它,其实就把每一个节点的左右孩子交换一下就可以了。

关键在于遍历顺序,前中后序应该选哪一种遍历顺序?

遍历的过程中去翻转每一个节点的左右孩子就可以达到整体翻转的效果。

注意只要把每一个节点的左右孩子翻转一下,就可以达到整体翻转的效果

这道题目使用前序遍历和后序遍历都可以,唯独中序遍历不方便,因为中序遍历会把某些节点的左右孩子翻转了两次!建议拿纸画一画,就理解了

那么层序遍历可以不可以呢?依然可以的!只要把每一个节点的左右孩子翻转一下的遍历方式都是可以的!

下面便和之前的遍历一样,从递归和迭代两种角度出发解题

递归法

我们下文以前序遍历为例,通过动画来看一下翻转的过程:

我们来看一下递归三部曲:

1、确定递归函数的参数和返回值

参数就是要传入节点的指针,不需要其他参数了,通常此时定下来主要参数,如果在写递归的逻辑中发现还需要其他参数的时候,随时补充。

返回值的话其实也不需要,但是题目中给出的要返回root节点的指针,可以直接使用题目定义好的函数,所以就函数的返回类型为TreeNode*

cpp 复制代码
TreeNode* invertTree(TreeNode* root)

2、确定终止条件

当前节点为空的时候,就返回

cpp 复制代码
if (root == NULL) return root;

3、确定单层递归的逻辑

因为是前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。

cpp 复制代码
swap(root->left, root->right);
invertTree(root->left);
invertTree(root->right);

基于这递归三步法,C++代码如下:

cpp 复制代码
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if (root == NULL) return root;
        swap(root->left, root->right);  // 中
        invertTree(root->left);         // 左
        invertTree(root->right);        // 右
        return root;
    }
};

迭代法

深度优先遍历

之前的博客中给出了前中后序迭代方式的写法,所以本题可以很轻松的写出如下迭代法的代码:

C++代码迭代法(前序遍历)

cpp 复制代码
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if (root == NULL) return root;
        stack<TreeNode*> st;
        st.push(root);
        while(!st.empty()) {
            TreeNode* node = st.top();              // 中
            st.pop();
            swap(node->left, node->right);
            if(node->right) st.push(node->right);   // 右
            if(node->left) st.push(node->left);     // 左
        }
        return root;
    }
};

如果这个代码看不懂的话可以再回顾一下代码随想录阅读笔记-二叉树【迭代遍历】-CSDN博客

我们在代码随想录阅读笔记-二叉树【统一迭代法】-CSDN博客中介绍了统一的写法,所以,本题也只需将文中的代码少做修改便可。

C++代码如下统一迭代法(前序遍历)

cpp 复制代码
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        stack<TreeNode*> st;
        if (root != NULL) st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node != NULL) {
                st.pop();
                if (node->right) st.push(node->right);  // 右
                if (node->left) st.push(node->left);    // 左
                st.push(node);                          // 中
                st.push(NULL);
            } else {
                st.pop();
                node = st.top();
                st.pop();
                swap(node->left, node->right);          // 节点处理逻辑
            }
        }
        return root;
    }
};
广度优先遍历

也就是层序遍历,层数遍历也是可以翻转这棵树的,因为层序遍历也可以把每个节点的左右孩子都翻转一遍,代码如下:

cpp 复制代码
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        queue<TreeNode*> que;
        if (root != NULL) que.push(root);
        while (!que.empty()) {
            int size = que.size();
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                swap(node->left, node->right); // 节点处理
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
        }
        return root;
    }
};
相关推荐
学逆向的几秒前
汇编——位运算
开发语言·汇编·算法·网络安全
可编程芯片开发15 分钟前
基于simulink的PEM燃料电池控制系统建模与仿真,对比PID,积分分离以及滑模控制器
算法
学究天人31 分钟前
数学公理体系大全:Comprehensive Collection of Mathematical Axiom Systems(卷2)
算法·数学建模·动态规划·图论·抽象代数·拓扑学
m0_669649461 小时前
医院发电机:安装与维护的区别要点
笔记
玛卡巴卡ldf1 小时前
【LeetCode 手撕算法】(细节知识点总结)
java·数据结构·算法·leetcode·力扣
风曦Kisaki1 小时前
# Linux实战笔记-HIS项目实战Day01:版本控制与Git基础
linux·笔记·git
wanzehongsheng2 小时前
零碳产业园光伏园区光伏电站追踪对比固定:发电增益技术边界分析
算法·光伏发电·光伏·零碳园区·太阳能追光·低碳环保·追踪电站
三品吉他手会点灯2 小时前
嵌入式机器学习 - 学习笔记1.0.1 - 从 Alexa 到 TinyML:为什么机器学习开始跑进微控制器?
人工智能·笔记·嵌入式硬件·学习·机器学习
KobeSacre2 小时前
CyclicBarrier 源码
java·jvm·算法
手写码匠2 小时前
注意力机制全家桶:从 Multi-Head 到 GQA 再到 Flash Attention 的手写实现
人工智能·深度学习·算法·aigc