【二叉树】遍历二叉树

news2024/11/20 15:30:06

前言

二叉树有前中后序和层序四种常用的遍历方式,今天我们来学习一下如何用这四种方法遍历二叉树。
前序:根、左、右
中序:左、右、根
后序:左、右、根
层序:第一层、第二层…

递归

递归是一种将复杂问题不断细分成小问题的方法。
既然是划分大问题为小问题,就要考虑明白什么时候是最小的问题,也就是我们常说的终止条件,就拿前序遍历举例子:
前序遍历要求我们按根、左、右的顺序去访问树,那我们访问完根节点,就可以将问题转换为子问题去访问他的左子树了。
当访问完根节点,再去访问根的左节点,当这个根的左节点访问完毕,最后去访问根的右节点,当遇到空的时候就终止。
在这里插入图片描述

  • 前序
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        Traversal(root,result);
        return result;
    }

    void Traversal(TreeNode* cur,vector<int>& result){
        if(cur == NULL){
            return; 
        }
        result.push_back(cur->val);      
        Traversal(cur->left, result);
        Traversal(cur->right, result);
    }
};
  • 中序
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        Traversal(root,result);
        return result;
    }

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

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

非递归

递归算法简单易懂,但是递归是要开辟栈帧的,栈的大小一般只有8M左右大小,递归调用层数太深很容易爆栈,因此我们还要学习如何通过非递归的方式进行遍历二叉树

非递归遍历也是大事化小的思想,拿前序遍历来讲,即先将左路节点全部入栈,root的所有左路节点入栈后,再进入到栈顶元素的右树(如果有的话),重复这个过程,即完成了前序遍历。

  • 前序
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        //前序遍历:根、左、右
        stack<TreeNode*> st;
        vector<int> v;

        TreeNode* cur = root;
        while(cur || !st.empty())
        {
            //开始访问一棵树
            //1.左路节点
            //2.左路节点的右子树
            while(cur)
            {
                v.push_back(cur->val);
                st.push(cur);
                cur = cur->left;
            }

            //开始访问右子树
            TreeNode* top = st.top();
            st.pop();

            //访问右子树,转换为子问题
            cur = top->right;
        }

        return v;
    }
};
  • 中序
    中序要按照左、根、右的方式遍历一棵树,还是一样一路并入root的左路节点,直到子问题变成左树为空的节点,这样直接将这个节点读取,再走他的右树(如果有右树的话),重复上面的逻辑即可。
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        //中序:左 根 右
        stack<TreeNode*> st;
        vector<int> v;

        TreeNode* cur = root;
        while(cur || !st.empty())
        {
            while(cur)
            {
                st.push(cur);
                cur = cur->left;
            }

            //加入节点,因为左边一定是空了
            TreeNode* top = st.top();
            st.pop();
            v.push_back(top->val);
            
            //去右树
            cur = top->right;
        } 

        return v;
    }
};
  • 后序
    后序与前面两者略有不同,后序在什么时候能够读取节点呢?必须在左右树(节点)都访问完成后才可以访问根节点,我们是将左路节点一路压到栈里的,由于栈先进后出,也就是说走到任意一个节点,必然已经走过了他的左路节点。
    如果右树不存在,我们自然可以直接访问这个节点,但如果右树存在,我们还是要按照刚开始的步骤压入左路节点,这样肯定在这颗右树处理完毕后再访问到这个节点,这时候左右树都已访问完毕,可以访问这颗树了,因此需要一个指针来记录我们上个元素访问的是谁,如果是这个节点的右子树的话,就可以访问这个节点。
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        //后序:左 右 根
        stack<TreeNode*> st;
        vector<int> v;

        TreeNode* cur = root;
        TreeNode* prev = nullptr;
        while(cur || !st.empty())
        {
            while(cur)
            {
                st.push(cur);
                cur = cur->left;
            }

            TreeNode* top = st.top();
            if(top->right == nullptr || top->right == prev)
            {
                v.push_back(top->val);
                st.pop();

                prev = top;
            }
            else
            {
                cur = top->right;
            }
        }

        return v;
    }
};

层序遍历

层序遍历就是一层一层遍历二叉树,如图:
在这里插入图片描述
要实现层序遍历我们要借助栈的数据结构,基本思路为:
先将根节点压入栈,访问完一个节点就将这个节点的子节点都入队列(如果有的话),以此类推,每次出队都会带来两个入队列。这一层出完,剩下的就都是下一层的了。

class Solution{
public:
    vector<vector<int>> levelOrder(TreeNode* root){
        vector<vector<int>> vv;
        int levelSzie = 0;/*表示当前层有多少个元素*/
        
        queue<TreeNode*> que;
        if(root)
        {
            que.push(root);
            levelSzie = 1;
        }
        while(!que.empty())
        {
            vector<int> v;
            while(levelSzie--)
            {
                TreeNode* node = que.front();
                que.pop();

                v.push_back(node->val);

                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
            }
            vv.push_back(v);
            levelSzie = que.size();
        }

        return vv;
    }
};

结语

以上就是本篇文章的全部内容了,希望对你理解二叉树的遍历有所帮助,我们下次再见~

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

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

相关文章

RHCE(五)

目录 一.判断当前磁盘剩余空间是否有20G&#xff0c;如果小于20G&#xff0c;则将报警邮件发送给管理员&#xff0c;每天检查一次磁盘剩余空间 1.创建脚本test1.sh 2.下载邮件服务并执行 3.测试 4.做计划任务 二.判断web服务是否运行&#xff08;1、查看进程的方式判断该程…

ChatGPT 速通手册——模仿唐诗宋词,和模仿莎士比亚十四行诗的中英文差距

模仿唐诗宋词&#xff0c;和模仿莎士比亚十四行诗的中英文差距 根据前文介绍的三大反例特性&#xff0c;我们可以尝试给出几个典型的反例。比如诗词创作&#xff0c;尤其是长短句约束更加严格的词牌&#xff0c;对照反例特性&#xff1a; 有明确且唯一可行的标准定义——一个…

Windows OpenVino安装squeezenet1.1失败 —— 已解决

作者主页&#xff1a;爱笑的男孩。的博客_CSDN博客-深度学习,YOLO,python领域博主爱笑的男孩。擅长深度学习,YOLO,python,等方面的知识,爱笑的男孩。关注算法,python,计算机视觉,图像处理,深度学习,pytorch,神经网络,opencv领域.https://blog.csdn.net/Code_and516?typecollec…

【排序】冒泡排序与快速排序(三个版本+非递归图示详解哦)

全文目录 引言冒泡排序快速排序思路实现Hoare版本快排优化 挖坑法前后指针法 快排非递归版本思路实现 总结 引言 在这篇文章中&#xff0c;将继续介绍排序算法&#xff1a;冒泡排序与快速排序&#xff1a; 它们都属于交换排序&#xff0c;即通过两两比较交换&#xff0c;将较…

小朋友崇拜圈+灌溉(JAVA解法)

目录 小朋友崇拜圈 题目链接&#xff1a; 题目描述 输入描述 输出描述 输入输出样例 灌溉 题目链接&#xff1a; 题目描述 输入描述 输出描述 输入输出样例 小朋友崇拜圈 题目链接&#xff1a; https://www.lanqiao.cn/problems/182/learning/?page5&first_c…

手撕源码(一)HashMap-JDK8

目录 1.使用示例2.new HashMap<>() 解析2.1 加载因子2.2 构造方法 3.put() 解析3.1 原始put(k, v)3.2 计算哈希1&#xff09;为什么要进行二次hash&#xff1f;2&#xff09;二次hash计算示例&#xff1a;3&#xff09;为什么使用 (length-1)&hash 而不是 hash%lengt…

互联网医院系统|线上问诊系统定制|互联网医院源码开发技术

当下医疗成为人们比较关注的问题&#xff0c;移动医疗技术不断的进步&#xff0c;互联网医院系统成为了医疗企业发展的必经之路&#xff0c;通过移动终端与互联网医院系统进行连接&#xff0c;实现医疗服务的远程交互与管理。可以使医疗机构的医生通过移动设备随时随地的查看患…

词的表示方法笔记——词向量+代码练习

词的表示方法&#xff1a; 一、one-hot&#xff08;最简单&#xff09; 独热编码是一种将单词转化为稀疏向量的方法&#xff0c;其中每个单词都表示为一个只有一个元素为1其余元素均为0的向量&#xff0c;其维度由词库的大小决定。。例如&#xff0c;对于包含 4个单词的词汇表 …

Python二分查找(折半查找)的实现

时间复杂度 最优时间复杂度&#xff1a;O(1) 最坏时间复杂度&#xff1a;O(logn) 思路 对有序的顺序表进行查找&#xff0c;以下标查找&#xff0c;每次取一半查找&#xff0c;如[1,2,3,4,5,6,7,8,9]&#xff0c;查3, 下标从0~8&#xff0c;(08)//24,对比折半到下标为2的元素…

【基础算法】栈和队列

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招算法的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于代码随想录进行的&#xff0c;每个算法代码参考leetcode高赞回答和…

手写axios源码系列二:创建axios函数对象

文章目录 一、模块化目录介绍二、创建 axios 函数对象1、创建 axios.js 文件2、创建 defaults.js 文件3、创建 _Axios.js 文件4、总结 当前篇章正式进入手写 axios 源码系列&#xff0c;我们要真枪实弹的开始写代码了。 因为 axios 源码的代码量比较庞大&#xff0c;所以我们这…

Xilinx FPGA下如何加快QSPI Flash加载速度

1. 首先&#xff0c;不同型号的FPGA对外部QSPI Flash支持的最高频率是不一样的。XC6SLX45支持的最高频率仅为26MHz&#xff0c; 而XC7K325T支持的最高频率高达66MHz。 所以&#xff0c;当我们添加 set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design] 的时候&…

特征选择算法 | Matlab实现基于互信息特征选择算法的分类数据特征选择 MI

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 特征选择算法 | Matlab实现基于互信息特征选择算法的分类数据特征选择 MI 部分源码 %

【1105. 填充书架】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给定一个数组 books &#xff0c;其中 books[i] [thicknessi, heighti] 表示第 i 本书的厚度和高度。你也会得到一个整数 shelfWidth 。 按顺序 将这些书摆放到总宽度为 shelfWidth 的书架上。 先…

题目3180:蓝桥杯2023年第十四届省赛真题-互质数的个数======及探讨互质专题

原题链接 https://www.dotcpp.com/oj/problem3162.html 想直接看题解的&#xff0c;跳转到第三次尝试即可。 已AC。 解析&#xff1a; &#xff08;1&#xff09;首先大家要知道什么叫互质&#xff1a; 以及它们的性质&#xff1a; 欧拉函数 在数论中&#xff0c;对正整…

世界读书日|这些值得程序员反复阅读的经典书

2023年是第28个世界读书日&#xff0c;每年的这个时候&#xff0c;小编都会准备一份书单与您分享。 与经典同行&#xff0c;伴书香成长。小编今天推荐一份值得程序员反复阅读的经典书。 1、浪潮之巅 第四版 这不只是一部科技产业发展历史集…… 更是在这个智能时代&#xff…

【远程工具】- MobaXterm 的下载、安装、使用、配置【Telnet/ssh/Serial】

一、MobaXterm 概述 在远程终端工具中&#xff0c;secureCrt 和 XShell 是两款比较有名的远程工具&#xff0c;但这两款软件现在都是收费的&#xff0c;有些公司不允许破解使用。今天就推荐一款免费的、免安装的、功能丰富的远程终端软件–MobaXterm。 MobaXterm是由Mobatek开…

JavaScript概述三(循环结构+BOM浏览器对象模型+JSON对象)

1.循环结构 1.1 普通循环(for循环,while循环,do……while循环) JavaScript中的普通循环和Java中的普通循环基本类似&#xff0c;此处以for循环为例&#xff0c;while和do……while便不再赘述。 <script type"text/javascript">var ary1new Array(1,false,嘿嘿…

Redis队列Stream、Redis多线程详解(三)

Redis中的线程和IO模型 什么是Reactor模式 &#xff1f; “反应”器名字中”反应“的由来&#xff1a; “反应”即“倒置”&#xff0c;“控制逆转”,具体事件处理程序不调用反应器&#xff0c;而向反应器注册一个事件处理器&#xff0c;表示自己对某些事件感兴趣&#xff0…

CTA进网测试《5G消息 终端测试方法》标准依据:YDT 3958-2021

GB 21288-2022 强制国标要求变化​ 与GB 21288-2007相比&#xff0c; 新国标主要有以下变化&#xff1a; 1. 增加职业暴露定义&#xff1a; 2. 增加吸收功率密度定义&#xff1a; 3. 增加不同频率、不同人体部位适用的暴露限值&#xff1a; 4. 增加产品说明书的注释&#xff1a…