代码随想录算法训练营day14|二叉树的递归遍历、二叉树的迭代遍历、二叉树的统一迭代法

二叉树的递归遍历

首先需要明确的一点是,前序中序和后序在二叉树的递归遍历中的区别仅在于递归函数中操作的顺序,前序是在遍历一个节点的左右子树前进行操作,中序是在遍历一个节点的左子树后进行操作再遍历右子树,而后序是在遍历完左右子树再进行操作。所以在递归函数中,仅是顺序的差别。前序中序和后序可简化为中左右、左中右和左右中,此外,写递归函数时,需要明确三点:

  • 确定递归函数的参数和返回值
  • 确定终止条件
  • 确定单层递归的逻辑

        在对二叉树的递归遍历中,递归函数需要传入树节点TreeNode * cur和vec数组进行操作,无实际返回值,所以函数为void,当递归操作时,若节点为空则返回,对每层递归的逻辑以前序遍历来说,先讲当前节点的val值传入数组vec中,之后遍历左子树,再之后遍历右子树。

代码随想录 (programmercarl.com)二叉树的递归遍历icon-default.png?t=N7T8https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E9%80%92%E5%BD%92%E9%81%8D%E5%8E%86.html#%E6%80%9D%E8%B7%AF看到递归就晕?带你理解递归的本质!_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV1UD4y1Y769/?spm_id_from=333.880.my_history.page.click&vd_source=fc4a6e70e3a87b7ea67c2024e326e7c5

前序遍历递归函数如下所示,

void traversal(TreeNode * cur, vector<int> & vec){//创建前序递归遍历函数
        if(cur == nullptr)//当当前遍历节点为空时,返回
            return;
        vec.push_back(cur->val);//中 将当前遍历节点的val值存入vec数组 *操作
        traversal(cur->left,vec);//遍历左子树
        traversal(cur->right,vec);//遍历右子树
    }

void traversal(TreeNode * cur, vector<int> & vec){//创建中序递归遍历函数
        if(cur == nullptr)//当当前遍历节点为空时,返回
            return;
        traversal(cur->left,vec);//遍历左子树
        vec.push_back(cur->val);//中 将当前遍历节点的val值存入vec数组 *操作
        traversal(cur->right,vec);//遍历右子树
    }

void traversal(TreeNode * cur, vector<int> & vec){//创建后序递归遍历函数
        if(cur == nullptr)//当当前遍历节点为空时,返回
            return;
        traversal(cur->left,vec);//遍历左子树
        traversal(cur->right,vec);//遍历右子树
        vec.push_back(cur->val);//中 将当前遍历节点的val值存入vec数组 *操作
    }

对于主函数体,只需传入节点,在函数体中创建一个ans数组,并传入traversal函数中。

vector<int> preorderTraversal(TreeNode* root) {
        vector<int> ans;
        traversal(root,ans);
        return ans;
    }

递归遍历树节点的时间复杂度和空间复杂度均为O(n)。

二叉树的迭代遍历

前序遍历

        考虑前序递归遍历的过程,若操作为打印,则先将自身val值打印后,对所有左子树打印,然后打印右子树,考虑使用栈来模拟前序遍历的过程(也是用栈来模拟递归的过程),由于栈是先入后出的数据结构,前序遍历结果左子树节点在右子树节点前,所以需先对右子树中节点入栈,再对左子树中节点入栈。然后是大致流程,创建结果数组ans,先判断根节点是否为空,若为空直接返回结果数组,否则将根节点入栈,在一个while循环中实现二叉树的迭代前序遍历,由于栈模拟的递归过程,当栈为空时,也就意味着递归结束,即我们遍历结果结果结束。所以while的循环条件为stack.size()!=0,在循环体内,创建一个指针指向当前节点,将其val值加入ans数组,之后再弹出栈,(第一次循环的pop为根节点,即第一次前序遍历要对根节点进行操作,之后因为我们是对栈是先加入右子树节点后加入左子树节点,所以会先对节点的左子树进行操作后对节点的右子树进行操作,完成前序遍历的过程),之后判断右子树的存在,若存在,将其入栈,判断左子树的存在,存在则将其入栈,这就是循环体内内容。

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> stack;
        vector<int> ans;
        if(root == nullptr){//当根节点为nullptr,直接返回ans
            return ans;
        }
        stack.push(root);
        while(stack.size()!=0){//栈不为空则循环
            TreeNode*cur = stack.top();//创建cur指针指向栈顶地址
            ans.push_back(cur->val);//将栈顶地址的值存入ans数组
            stack.pop();//出栈
            if(cur->right)//判断左右子树存在的情况,若存在,将其存入栈中,注意顺序,先右后左                
                         //出栈则为先左后右
                stack.push(cur->right);
            if(cur->left)
                stack.push(cur->left);
        }
        return ans;
    }
};

该算法的时间复杂度和空间复杂度均为O(n)。

中序遍历

        在遍历二叉树的节点时,创建遍历指针cur,先遍历左子树,依次将所有左节点全部入栈,当当前节点的左节点为空时,弹出栈中元素给遍历指针cur,并将cur指向的val传入数组中,完成中的操作,令cur = cur->right,并继续进行循环。算法的时间和空间复杂度均为O(n)。

class Solution {
public:
    // 定义一个函数,用于执行中序遍历
    vector<int> inorderTraversal(TreeNode* root) {
        // 创建一个空向量 ans,用于存储遍历的结果
        vector<int> ans;
        // 创建一个空栈 st,用于辅助遍历
        stack<TreeNode*> st;
        // 创建一个指针 cur,初始指向根节点
        TreeNode* cur = root;
        // 当 cur 指向的节点不为空或者栈 st 不为空时,进行循环
        while (cur != nullptr || !st.empty()) {
            // 如果 cur 指向的节点不为空,则将其压入栈 st 中,并移动 cur 指针到其左子节点
            if (cur != nullptr) {
                st.push(cur);
                cur = cur->left;
            }
            // 如果 cur 指向的节点为空,说明左子节点已经访问完毕,此时从栈 st 中弹出最上面的节点
            else {
                cur = st.top(); // 获取栈顶节点
                st.pop(); // 弹出栈顶节点
                // 将弹出的节点的值添加到 ans 向量中
                ans.push_back(cur->val);
                // 移动 cur 指针到其右子节点
                cur = cur->right;
            }
        }
        // 循环结束后,返回存储遍历结果的 ans 向量
        return ans;
    }
};

后序遍历

        考虑前序遍历和后序遍历的相似之处,调整一下前序遍历中左右节点的入栈顺序,让中左右变为中右左,之后再通过一个reverse即能实现后序遍历。

调整

//前序
if(cur->right)//判断左右子树存在的情况,若存在,将其存入栈中,注意顺序,先右后左                
                         //出栈则为先左后右
stack.push(cur->right);
if(cur->left)
stack.push(cur->left);

//后序
if(cur->left)
stack.push(cur->left);
if(cur->right)
stack.push(cur->right);
            

整体代码

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*> stack;
        vector<int> ans;
        if(root == nullptr){//当根节点为nullptr,直接返回ans
            return ans;
        }
        stack.push(root);
        while(stack.size()!=0){//栈不为空则循环
            TreeNode*cur = stack.top();//创建cur指针指向栈顶地址
            ans.push_back(cur->val);//将栈顶地址的值存入ans数组
            stack.pop();//出栈
            if(cur->left)
                stack.push(cur->left);
            if(cur->right)
                stack.push(cur->right);
        }
        reverse(ans.begin(),ans.end());//反转
        return ans;
    }
};

二叉树的统一迭代法

周末再看看

代码随想录 (programmercarl.com)二叉树的统一迭代法icon-default.png?t=N7T8https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E7%BB%9F%E4%B8%80%E8%BF%AD%E4%BB%A3%E6%B3%95.html#%E6%80%9D%E8%B7%AF

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/655669.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

3D点云焊缝提取 平面交线 投影

文章目录 1. 效果2. 思路3. 源码 1. 效果 2. 思路 计算点云法向量&#xff1b;计算点云位姿Pose;翻转Pose中的Z轴方向&#xff0c;使其一致&#xff1b;通过Pose的Z轴对点云进行方向过滤&#xff1b;对点云聚类&#xff1b;根据目标点云的高度提取目标点云&#xff1b;提取两块…

云计算-Amazon S3

亚马逊S3&#xff08;Amazon S3&#xff09; 亚马逊S3是一种云对象存储设施。我们将使用的对象将是您在个人计算机上常用的文件。亚马逊S3产品旨在可扩展到实际无限数量的对象和无限大小的对象&#xff0c;但我们在本实验室的练习中只会使用少量对象。当存储许多对象时&#xf…

微服务架构下的‘黑带’安全大师:Spring Cloud Security全攻略!

深入探讨了微服务间的安全通信、安全策略设计以及面对经典安全问题的应对策略。无论你是微服务的新手还是资深开发者&#xff0c;都能在本文中找到提升安全功力的秘籍。让我们一起成为微服务架构下的‘黑带’安全大师&#xff01; 文章目录 1. 引言微服务安全挑战与重要性Sprin…

前后端 | 低代码平台之 Erupt

前文提要 最近大家是不是都有那种危机感&#xff0c;项目变多了&#xff0c;工时压紧了&#xff0c;老板说&#xff0c;我不管你加不加班&#xff0c;我只看结果&#xff0c;项目经理说&#xff0c;我不管你用什么技术栈&#xff0c;我只要没BUG&#xff0c;测试说&#xff0c…

【SQL学习进阶】从入门到高级应用(一)

文章目录 MySQL命令行基本命令数据库表的概述初始化测试数据熟悉测试数据 &#x1f308;你好呀&#xff01;我是 山顶风景独好 &#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01; &#x1f49d;希望您在这里可以感受到一份轻松愉快的氛围&#x…

算法002:复写零

力扣&#xff08;LeetCode&#xff09;. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/duplicate-zeros/ 使用 双指针 来解题&#xff1a; 具体思路 如果是和00…

【Linux】线程安全及锁的使用

文章目录 前言一、锁1.定义一个锁变量2.pthread_mutex_init3.pthread_mutex_destroy4.pthread_mutex_lock/pthread_mutex_unlock5.静态变量锁和全局变量锁的初始化 二、问题描述及锁的运用三、RAII风格的锁 前言 临界资源: 在多个线程或进程间共享的资源. 临界区: 代码中访问临…

echarts-象形柱图

象形柱图 一般的柱图都是纯色柱图&#xff0c;使用象形柱图可以给柱图定义自己的样式。 样式的调节与柱图一样&#xff0c;核心在于symbol调节柱图的组成。 let options {tooltip: {},xAxis: {type: "category",data: ["d1", "d2", "d3&qu…

【CTF Web】NSSCTF 3868 [LitCTF 2023]这是什么?SQL !注一下 !Writeup(SQL注入+报错注入+括号闭合+DIOS)

[LitCTF 2023]这是什么&#xff1f;SQL &#xff01;注一下 &#xff01; 为了安全起见多带了几个套罢了o(▽)q 出题人 探姬 解法 先试试这个&#xff1a; )))))) or 11 -- 有结果了&#xff0c;但是这个 flag 是假的。 flag 可能在其他表里。用 hackbar 上 DIOS payload。 …

git教程(IDEA + 命令行)

首先假设你已经安装 git 且 已经初始化完成&#xff1a; // 初始化git config --global user.name "你的用户名" git config --global user.email "你的邮箱"在当前文件夹下创建一个仓库&#xff0c;且该文件夹下会有多个项目 首先在当前文件夹下新建git…

python--pycharm中将venv删除后怎么办

在终端中输入以下命令来创建一个新的虚拟环境&#xff08;可选&#xff09;&#xff1a; python -m venv venv 激活虚拟环境&#xff1a; Windows: .\venv\Scripts\activate选择自己项目的虚拟环境

网络故障排除—NAT-源进源出

多网络双出口一边是运营商A,一边是运营商B&#xff0c;将内网服务器分别映射到运营商B和运营商A出口。查了保证内部上网用户网速快管理员开启了运营商选路功能&#xff0c;运营商B的网站从运营商B出去&#xff0c;然后写有两条等价默认路由分别指向两个外网出口。营商A的网站从…

Angular(1):使用Angular CLI创建空项目

要创建一个空的 Angular 项目&#xff0c;可以使用 Angular CLI&#xff08;命令行界面&#xff09;。以下是使用 Angular CLI 创建一个新项目的步骤&#xff1a; 1、安装 Angular CLI&#xff1a; 打开你的命令行界面&#xff08;在 Windows 上是 CMD、PowerShell 或 Git Bas…

渲染管线——应用阶段

知识必备——CPU和GPU 应用阶段都做了什么 应用阶段为渲染准备了什么 1.把不可见的数据剔除 2.准备好模型相关数据&#xff08;顶点、法线、切线、贴图、着色器等等&#xff09; 3.将数据加载到显存中 4.设置渲染状态&#xff08;设置网格需要使用哪个着色器、材质、光源属性等…

区间类贪心,蓝桥云课 打折

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 0打折 - 蓝桥云课 (lanqiao.cn) 二、解题报告 1、思路分析 思路很简单&am…

回答篇二:测试开发高频面试题目

引用之前文章&#xff1a;测试开发高频面试题目 本篇文章是回答篇&#xff08;持续更新中&#xff09; 1. 在测试开发中使用哪些自动化测试工具和框架&#xff1f;介绍一下你对其中一个工具或框架的经验。 a. 测试中经常是用的自动化测试工具和框架有Selenium、Pytest、Postman…

“盲人独立生活技能提升方案”:科技点亮希望之光

在追求平等与包容的社会进程中&#xff0c;盲人群体的独立生活能力提升成为了重要议题。随着科技的飞速发展&#xff0c;一款名为“蝙蝠避障”的辅助软件应运而生&#xff0c;以其独特的实时避障和拍照识别功能&#xff0c;为盲人在旅行乃至日常生活中开辟了新的可能。这不仅是…

OS复习笔记ch7-1

存储的基本管理需求 重定位 重定位(Relocation)&#xff1a;需要解决可执行文件中地址&#xff08;指令和数据&#xff09;和内存地址的对应。 一般有两种比较常见的重定位方式&#xff1a; 静态重定位(static relocation)&#xff1a;当程序被装入内存时&#xff0c;一次性…

刷代码随想录有感(81):贪心算法——分发饼干

题干&#xff1a; class Solution { public:int findContentChildren(vector<int>& g, vector<int>& s) {sort(g.begin(), g.end());sort(s.begin(), s.end());int index s.size() - 1;int res 0;for(int i g.size() - 1; i > 0; i--){if(index >…

SpringBoot使用redis结合mysql数据库(黑名单)渲染商品详情界面

目录 一、界面效果 二、前端代码 三、后端代码&#xff08;redisblacklist&#xff09; 3.1 ProducatController 3.2 ProductService 3.3 ProductDao 3.4 映射文件 一、界面效果 二、前端代码 商品详情前端代码 <template><van-nav-bartitle"商品详情&quo…