二叉树的递归遍历与迭代遍历(图示)

news2025/1/31 8:07:00

文章目录

  • 前言
    • 1. 二叉树的递归遍历(一入递归深似海,从此offer是路人)
      • 1.1 [前序遍历](https://leetcode.cn/problems/binary-tree-preorder-traversal/)
      • 1.2 [中序遍历](https://leetcode.cn/problems/binary-tree-inorder-traversal/)
      • 1.3 [后序遍历](https://leetcode.cn/problems/binary-tree-postorder-traversal/)
    • 2.二叉树的迭代遍历(听说递归能做的,栈也能做?)
      • 2.1 前序遍历
      • 2.2 中序遍历
      • 2.3 后序遍历
  • 后记

前言

本文将讲述二叉树递归与迭代的相关知识。

🕺作者: 迷茫的启明星
专栏:【数据结构从0到1】

😘欢迎关注:👍点赞🙌收藏✍️留言

🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的很重要,有问题可在评论区提出,感谢阅读!!!

持续更新中~

1. 二叉树的递归遍历(一入递归深似海,从此offer是路人)

首先我们要知道递归的三要素是什么?

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

    我们看到一个递归确定它在递归过程中需要处理哪些参数就需要加上那些,并且还要注意返回值是否合理

  2. 确定终止条件

    我们需要判断递归什么时候停止,以及思考怎么停止

  3. 确定递归的逻辑

    递归过程中的操作往往是重复的或者说是相似的,只是改变了一些参数

以二叉树前序遍历为例:

  1. 确定递归函数参数及返回值

    参数里需要返回遍历情况的数组、树的节点

    void traval(TreeNode* cur,vector<int> &result)
    
  2. 确定终止条件

    前序遍历上面时候停止呢?

    在前序遍历的时候的顺序是”中左右“,也就是先访问当前节点,再访问左节点,左节点访问完了,直到遇到没有孩子的节点才返回,访问上一个节点的右节点,再访问左节点,左节点访问完了,直到遇到没有孩子的节点才返回,也就是说返回条件是节点为nullptr时。

     if(cur==nullptr)return;
    
  3. 确定递归逻辑

    上面已经阐述了递归的逻辑,也就是先访问当前节点,再访问左节点和右节点。

    result.push_back(cur->val);
    traval(cur->left,result);
    traval(cur->right,result);
    

由此我们已经完成了二叉树前序遍历的分析工作

那么代码如下,中序遍历和后序遍历逻辑同样如此就再啰嗦。

1.1 前序遍历

class Solution {
public:
    void traval(TreeNode* cur,vector<int> &result)
    {
        if(cur==nullptr)return;
        result.push_back(cur->val);
        traval(cur->left,result);
        traval(cur->right,result);
    }

    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        traval(root,result);
        return result;
    }
};

1.2 中序遍历

class Solution {
public:

    void traval(TreeNode*cur,vector<int>& result)
    {
        if(cur==nullptr)return;
        traval(cur->left,result);
        result.push_back(cur->val);
        traval(cur->right,result);

    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        traval(root,result);
        return result;
    }
};

1.3 后序遍历

class Solution {
public:
    void traval(TreeNode*cur,vector<int> &result)
    {
        if(cur==nullptr)return;
        traval(cur->left,result);
        traval(cur->right,result);
        result.push_back(cur->val);
    }
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        traval(root,result);
        return result;
    }
};

2.二叉树的迭代遍历(听说递归能做的,栈也能做?)

为什么可以用栈来实现递归呢?

其实编译器在递归的时候本质就是在调用栈,当一个函数里面嵌套一个函数,在调用的时候,只有里面的函数都返回完了,这个函数才返回,也就是后进先出原则。

2.1 前序遍历

那么前序遍历的迭代是怎么一回事呢?

假如说有个二叉树是这样的:

在这里插入图片描述

它的迭代过程应该是这样的:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

那么代码应该怎么表述呢?

  1. 首先应该建立一个存储顺序的数组,一个以树节点为元素的栈
  2. 然后需要判断树是否是空树,是则直接返回无元素数组
  3. 需要建立一个循环,但在循环开始前需要把树的根节点push进去
  4. 然后需要判断循环的停止条件是什么?根据上面图示可知只要栈不为空,循环就不会停止,于是循环的条件就是栈不为空
  5. 在循环里面需要一个变量来存储pop掉的节点
  6. 为了保持”中 左 右“的顺序就需要先让右节点先进,然后左节点进,以此保证左节点先弹出

代码如下:

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        if(root==nullptr)return result;
        st.push(root);
        TreeNode* cur=nullptr;
        while(!st.empty())
        {
            cur=st.top();
            st.pop();
            result.push_back(cur->val);
            if(cur->right)st.push(cur->right);
            if(cur->left)st.push(cur->left);

        }
        
        return result;
    }
};

2.2 中序遍历

前面我们实现了前序遍历的迭代法,但是中序遍历是否像递归那样只要交换顺序就可以了呢?并非如此

因为刚刚前序遍历时我们有两个操作:

  1. 处理:将元素放进result数组中
  2. 访问:遍历节点

它们在前序遍历时是同时发生的

但是中序遍历不同

中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进result数组中),这就造成了处理顺序和访问顺序是不一致的。

那么在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。

图示如下:

在这里插入图片描述

代码如下:

class Solution {
public:

    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        TreeNode*cur=root;
        while(cur!=nullptr||!st.empty())
        {
            if(cur!=nullptr)
            {
                st.push(cur);
                cur=cur->left;
            }
            else
            {
                cur=st.top();
                result.push_back(cur->val);
                st.pop();
                cur=cur->right;
            }
        }
        return result;
    }
};

2.3 后序遍历

后序遍历相当于前序遍历的反面,就不画图了

只需要了解一下思路即可

  1. 声明一个栈,将根节点加入栈中;
  2. 初始化一个变量pre为null,表示上一个访问的节点;
  3. 若栈不为空,则进行如下操作:
    • 取出栈顶元素top;
    • 如果top没有左右孩子或者前一个访问的节点是其左孩子或右孩子,则访问该节点并将其弹出栈
    • 否则,先将其右孩子入栈,再将左孩子入栈,保证左孩子先弹出。
class Solution {
public:

    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        if(root==NULL)return result;
        TreeNode*cur=NULL;
        TreeNode*pre=NULL;
        st.push(root);
        while(!st.empty())
        {
            cur=st.top();
            if((cur->left==NULL&&cur->right==NULL)||
            (pre!=NULL&&(pre==cur->left||pre==cur->right)))
            {
                result.push_back(cur->val);
                st.pop();
                pre=cur;
            }
            else
            {
                if(cur->right!=NULL)st.push(cur->right);
                if(cur->left!=NULL)st.push(cur->left);
            }
        }

        return result;
    }
};

后记

本篇主要讲述了二叉树的递归遍历与迭代遍历,我们发现递归遍历只要交换代码实现的顺序就可以实现前中后遍历,而迭代法则需要限定不同的条件,这是因为处理顺序和访问顺序不一致而造成的,那么有没有办法统一它们呢?我们下篇会讲到的~

感谢大家支持!!!

respect!

下篇见!在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

实验一 Python基础编程

实验一 Python基础编程 只为给原因学习编程的同学提供一个思路&#xff0c;让编程更简单&#xff01;&#xff01;&#xff01; 本博主擅长整理粉丝的私信&#xff01;只要你有需求就可以告诉博主&#xff01;博主可以帮你解决并发表&#xff01; 一、实验学时 2学时 二、实…

docker发布到dockerhub报错denied: requested access to the resource is denied

docker发布到dockerhub报错denied: requested access to the resource is denied 解决方案 修改发布的镜像的REPOSITORY为自己的账户名镜像&#xff0c;比如我的用户名是luobotoutou123。docker tag tomcat02:1.0 luobotoutou123/tomcat02:1 然后发布镜像 到dockerhub远程仓库…

学习杂记 2023.5.13 单词背诵

目录 鼠标上的DPI是什么&#xff1f; 鼠标上的DPI是什么&#xff1f; DPI是英文Dots Per Inch的缩写&#xff0c;意思是每英寸点数。在计算机中&#xff0c;DPI通常用于描述指针设备&#xff08;例如鼠标&#xff09;的精度。在鼠标上&#xff0c;DPI指的是鼠标移动时指针在屏…

[图神经网络]ViG(Vision GNN)网络代码实现

论文解读&#xff1a; [图神经网络]视觉图神经网络ViG(Vision GNN)--论文阅读https://blog.csdn.net/weixin_37878740/article/details/130124772?spm1001.2014.3001.5501代码地址&#xff1a; ViGhttps://github.com/huawei-noah/Efficient-AI-Backbones/tree/master/vig_p…

Hive之DDL

目录 对数据库操作&#xff1a; 创建数据库&#xff1a; 查看数据库信息&#xff1a; 1.查看基本信息&#xff1a; 2.查看详尽信息&#xff1a; 删除数据库&#xff1a; 1.简单语法&#xff1a; 2.复杂语法&#xff1a; 对表操作&#xff1a; 创建表&#xff1a; 1.普…

JVM-内存结构

✅作者简介&#xff1a;热爱Java后端开发的一名学习者&#xff0c;大家可以跟我一起讨论各种问题喔。 &#x1f34e;个人主页&#xff1a;Hhzzy99 &#x1f34a;个人信条&#xff1a;坚持就是胜利&#xff01; &#x1f49e;当前专栏&#xff1a;JVM &#x1f96d;本文内容&…

《程序员的底层思维》读书笔记

人是能够习惯于任何环境的生物&#xff0c;之前你认为自己难以克服的困难&#xff0c;慢慢都会适应了。 维克多弗兰克《活出生命的意义》 文章目录 人是能够习惯于任何环境的生物&#xff0c;之前你认为自己难以克服的困难&#xff0c;慢慢都会适应了。 基础思维能力逻辑思维批…

每日学术速递5.12

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.ImageBind: Holistic AI learning across six modalities 标题&#xff1a;ImageBind&#xff1a;跨六种模式的整体人工智能学习 作者&#xff1a;Mengyuan Yan Jessica Lin Mont…

支付系统设计三:渠道网关设计04-渠道数据补全

文章目录 前言一、交易信息准备1. MessageDescription内容2. 交易信息填充3. 开户机构信息填充4. 省市区域信息填充5. 银行信息填充 二、路由处理三、支付渠道数据补全1.服务端支付渠道获取2. 支付渠道通用数据补全2.1 支付渠道账户信息补全2.1 商户信息补全结束 3. 支付渠道差…

具有噪声标签的鲁棒医学图像分割的点类仿射损失校正

文章目录 Joint Class-Affinity Loss Correction for Robust Medical Image Segmentation with Noisy Labels摘要本文方法Differentiated Affinity Reasoning (DAR)Class-Affinity Loss Correction (CALC)Class-Level Loss CorrectionAffinity-Level Loss CorrectionClass-Affi…

AcWing算法提高课-1.3.4数字组合

宣传一下算法提高课整理 <— CSDN个人主页&#xff1a;更好的阅读体验 <— 本题链接&#xff08;AcWing&#xff09; 点这里 题目描述 给定 N N N 个正整数 A 1 , A 2 , … , A N A_1,A_2,…,A_N A1​,A2​,…,AN​&#xff0c;从中选出若干个数&#xff0c;使它们…

轻松搭建冒险岛服务器-冒险岛私服搭建详细教程

想要拥有一个属于自己的冒险岛世界吗&#xff1f;想要一步步学习如何架设冒险岛服务器吗&#xff1f;本文将从如何选择服务器、安装系统、配置环境、搭建数据库、部署网站、上传文件、启动服务等8个方面&#xff0c;一步步为大家详细讲解冒险岛架设教程。让你轻松打造属于自己的…

sql 性能优化基于explain调优

文章目录 Explain分析&#xff1f;问题描述解决方案 Explain分析&#xff1f; 关于Explain具体可以干什么&#xff0c;有哪些优缺点&#xff0c;本博主的文章有写到&#xff0c;这是链接地址: 点击这里查看. 下面来说下Explain在项目实战中&#xff0c;如何去进行优化。 问题…

7年老人,30岁的测试说辞就辞,“人员优化”4个字,泰裤辣...

前几天&#xff0c;一个认识了好几年在大厂做测试的程序员朋友&#xff0c;年近30了&#xff0c;在公司做了7年了&#xff0c;一直兢兢业业&#xff0c;最后还是却被大厂以“人员优化”的名义无情被辞&#xff0c;据他说&#xff0c;有一个月散伙饭都吃了好几顿…… 在很多企业…

【ChatGPT】国内免费使用ChatGPT镜像

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 目录 什么是ChatGPT镜像&#xff1f; 亲测&#xff1a; 一、二狗问答(AI对话) 二、AiDuTu 三、WOChat 四、ChatGPT(个人感觉最好用) 我们可以利用ChatGPT干什么&#xff1f; 一、三分…

薪人薪事 java开发实习一面

目录 1.常用数据结构&#xff0c;区别及使用场景2.数组和链表在内存中数据的分布情况3.HashMap底层数据结构4.put操作5.JVM内存区域6.各个区域存放什么东西7.创建一个对象&#xff0c;内存怎么分配的8.堆中内存怎么划分&#xff0c;gc怎么回收9.IOC 原理10.Bean存放在哪里11.AO…

支付系统设计三:渠道网关设计05-交易持久化

文章目录 前言一、领域模型持久化服务工厂二、聚合创建工厂1. 模型创建1.1 获取域模型Class1.2 新建模型1.3 数据填充 2. 模型持久化2.1 获取域模型对应的仓储2.2 调用域模型仓储进行持久化 总结 前言 本篇将解析交易信息入库&#xff0c;即对上送的参数&#xff0c;在进行校验…

关于ASA广告归因接入方法

投放苹果ASA广告&#xff0c;提高 app 曝光率、下载量的增长&#xff0c;那么我们该如何从后台看到投放广告的效果呢&#xff1f; 我们可以借助Apple Ads归因API。那什么是归因&#xff1f;什么又是API呢&#xff1f; 归因&#xff1a;可以给用户打标签&#xff0c;然后看他在…

[GUET-CTF2019]encrypt 题解

本题是输入了一个字符串&#xff0c;进行了rc4加密&#xff0c;和魔改的base64加密 RC4算法初始化函数 RC4加密过程 魔改的base64加密 最后加密的字符串是byte_602080 我们可以将byte_602080提取出来&#xff0c;下面是提取数据的IDC脚本&#xff0c;得到了密文 #include<…

赫夫曼树和赫夫曼编码详解

目录 何为赫夫曼树&#xff1f; 赫夫曼树算法 赫夫曼编码 编程实现赫夫曼树 编程实现赫夫曼编码 编程实现WPL 总代码及分析 何为赫夫曼树&#xff1f; 树的路径长度&#xff1a;从树根到每一结点的路径长度之和 结点的带权路径长度&#xff1a;从树根到该结点的路径长度…