代码随想录算法训练营DAY14|C++二叉树Part.1|二叉树的递归遍历、二叉树的迭代遍历、二叉树的统一迭代法

news2024/11/26 4:35:09

文章目录

  • 二叉树的递归遍历
    • 思路
    • CPP代码
  • 二叉树的迭代遍历
    • 思路
      • 前序遍历
      • 后序遍历
      • 后序遍历
  • 二叉树的统一迭代法

二叉树的递归遍历

144.二叉树的前序遍历、145.二叉树的后序遍历、94.二叉树的中序遍历

文章讲解:二叉树的递归遍历

视频讲解:每次写递归都要靠直觉? 这次带你学透二叉树的递归遍历!

状态:搞清楚本题就一定要先搞清楚递归是什么,曾经可能需要靠栈来想想递归的工作流程,现在我觉得树结构就很好得向我们展示了递归这个方法。

思路

首先搞清楚前中后序的遍历方法,这里以前序遍历进行举例。

20200806191109896

如果用递归的思路来思考前序遍历,其实就是每到一个结点,我们就对其先进性处理,然后分别去遍历左、右孩子。

要写明白递归,就要有三大要素:

  • 确定递归的参数和返回值:这里我们遍历到结点处,通过数组进行存储,所以返回值是void,数组作为参数传进来即可:
void traversal(TreeNode* cur, vector<int> res){
  ...
}
  • 确定终止条件:在递归的过程中,如何算是递归结束了呢,当然是当前遍历的节点是空了,那么本层递归就要结束了,所以如果当前遍历的这个节点是空,就直接return,代码如下:
if (cur == NULL) return;
  • 确定单层递归的逻辑:前序遍历是中左右的循序,所以在单层递归的逻辑,是要先取中节点的数值,代码如下:
vec.push_back(cur->val);    // 中
traversal(cur->left, vec);  // 左
traversal(cur->right, vec); // 右

剩下的中序遍历、后序遍历只要把遍历顺序换个位置即可:

//中序
traversal(cur->left, vec);  // 左
vec.push_back(cur->val);    // 中
traversal(cur->right, vec); // 右

//后序
traversal(cur->left, vec);  // 左
traversal(cur->right, vec); // 右
vec.push_back(cur->val);    // 中

CPP代码

//前序遍历
class Solution {
public:
    void traversal(TreeNode* cur, vector<int>& vec) {
        if (cur == NULL) return;
        vec.push_back(cur->val);    // 中
        traversal(cur->left, vec);  // 左
        traversal(cur->right, vec); // 右
    }
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        traversal(root, result);
        return result;
    }
};

二叉树的迭代遍历

144.二叉树的前序遍历、145.二叉树的后序遍历、94.二叉树的中序遍历

文章讲解:二叉树的迭代遍历

视频讲解:写出二叉树的非递归遍历很难么?(前序和后序)写出二叉树的非递归遍历很难么?(中序))

状态:迭代中的第一步没处理好,一直在想我怎么在迭代中让结点遍历起来呢?本质就是栈里面存储的其实不是结点数值,而是把整个结点都存储进去了。

迭代遍历总结两点:栈内存储的是结点,这样才知道如何结点是如何遍历起来的;把结点存储在栈的核心就是,只要不处理,就不应该弹出,处理的时候才弹出

思路

这篇文章已经把思路解释的非常清楚了:二叉树的递归遍历、二叉树的迭代遍历、二叉树的统一迭代法

前序遍历

  • 搞清楚栈内到底存的是值还是结点:存储结点,如果存储值的话,我们没有手段去遍历二叉树了

记得提前存入根结点,如果没有根结点,直接返回空。

  • 搞清楚循环体内如何去遍历整个二叉树:

同第三点的强调,栈顶元素是哪一个,我们才遍历哪一个

  • 搞清楚在模拟出栈入栈过程中,我们关注的其实是栈顶结点,栈顶结点跑到哪里,我们就遍历哪个子树。
TreeNode* node = st.top();
st.pop();
if(node->right) st.push(node->right);
if(node->left) st.push(node->left);

整体代码如下:

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> result;
        if (root == NULL) return result;
        st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();                       // 中
            st.pop();
            result.push_back(node->val);
            if (node->right) st.push(node->right);           // 右(空节点不入栈)
            if (node->left) st.push(node->left);             // 左(空节点不入栈)
        }
        return result;
    }
};

后序遍历

前序遍历是中左右-----(调整代码左右循环)---->中右左----(反转result数组)---->左右中

我们的后序遍历就是左右中!所以前序遍历的代码很重要!

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> result;
        if (root == NULL) return result;
        st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();                       // 中
            st.pop();
            result.push_back(node->val);
            if (node->left) st.push(node->left);             // 左(空节点不入栈)
            if (node->right) st.push(node->right);           // 右(空节点不入栈)
        }
      	reverse(result.begin(), result.end());
        return result;
    }
};

后序遍历

后序遍历最难的点就在于,我们遍历的结点不是我们要处理的结点,我们遍历过该结点后可能要到后面才能去处理,这样应该怎么办呢?一个办法:借助指针

我们用指针来遍历整个二叉树,然后用栈来存储遍历的顺序

再进一步,中序遍历的规矩就是,左孩子不是空,左孩子压栈,如果空了(左),就要处理栈顶元素(中),然后压入右孩子,如果右孩子是空,那就继续处理栈顶元素和栈顶的右孩子(右)。

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
			stack<int> st;
      vector<int> result;
      TreeNode* cur = root;
      while(cur != NULL|| !st.empty()){	//0 1 则 1	
        	if(cur != NULL){
            st.push(cur);
            cur = cur->left;
          }else{
            cur = st.top();
            st.pop();
            result.push_bacl(cur->val);
            cur->right;
          }
      }
      return result;
    }
};

二叉树的统一迭代法

文章讲解:二叉树的统一迭代法

状态:感觉有点厉害,以后有时间在进行研究。

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

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

相关文章

寒冬已逝,“量子春天”正来

最近&#xff0c;全球对量子技术领域的私人投资有所下降&#xff0c;引发了一些观点认为这个领域可能正逐渐衰退。 政治家、资助者和投资者并不总是以科学为关注焦点。然而&#xff0c;某些科技领域偶尔会成为热点&#xff0c;正如20世纪50年代核能技术的兴起&#xff0c;那时人…

ios 之 netty版本swiftNio(socket创建)

SwiftNio 简介 用于高性能协议服务器和客户端的事件驱动、无阻塞的网络应用程序框架。 SwiftNIO是一个跨平台异步事件驱动的网络应用程序框架&#xff0c;用于快速开发可维护的高性能协议服务器和客户端。 这就像Netty&#xff0c;但是为Swift写的。 Xcode引入swiftNio 在实…

联诚发2024第二季度高质量发展工作推进会议顺利召开

4月1日上午&#xff0c;联诚发LCF以“稳中创新•产业升级•高质量发展”为主题的第二季度企业高质量发展工作推进大会在联诚发深圳总部隆重召开。会议总结上一季度的工作成果&#xff0c;分析研判当前形势&#xff0c;谋划部署下一季度工作&#xff0c;团结动员公司全体职工凝心…

Web3:数字化社会的下一步

随着技术的不断进步和互联网的发展&#xff0c;我们正逐渐迈入一个全新的数字化社会阶段。在这个新的时代&#xff0c;Web3作为数字化社会的重要组成部分&#xff0c;将发挥着举足轻重的作用。本文将探讨Web3在数字化社会中的意义、特点以及对未来发展的影响。 1. 重新定义数字…

设计模式——行为型——责任链模式Chain Of Responsibility

请求类 public class ApproverRequest {private int type;//请求批准的类型private float price;//请求的金额private int id;//请求的编号 } 审批人抽象类 public abstract class ApproverPerson {protected ApproverPerson next;protected String name;//审批过程public a…

【好书推荐4】图机器学习

【好书推荐4】图机器学习 写在最前面编辑推荐内容简介作者简介目录前言/序言本书读者内容介绍 &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 2024每日百字篆刻时光&#xff0c;感谢你的陪伴与支持 ~ &#x1f680; 欢迎一起踏上探险之旅&#xff0c;挖掘无限可能…

nut-ui中的menu 菜单组件的二次封装

这个菜单组件 一般可以直接用到项目里 如果复用性不强的话 直接使用 但是有一个问题 如果很多地方都需要用到这个组件 我们可以把这个组件二次封装一下 <template><div class"cinema-search-filter-component"><nut-menu><template #icon>&…

交流耦合和直流耦合

一、 AC和DC定义 在选择输入模式时&#xff0c;可能选择不同的耦合方式会影响到数据中的频率成分。大多数信号都有AC成分和DC成分&#xff0c;DC成分是0Hz的部分&#xff0c;对应时域信号中的直流分量&#xff08;或称为直流偏置&#xff09;&#xff0c;AC成分是信号中的交变部…

VCRUNTIME140_1.dll丢失是怎么回事?多种解决方法帮你搞定

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“vcruntime140_1.dll文件丢失”。那么&#xff0c;这个文件是什么&#xff1f;它的作用是什么&#xff1f;当它丢失时&#xff0c;会提示什么样的错误信息呢&#xff1f;本文将详细介绍vcru…

谷粒商城实战(009 缓存-分布式锁)

Java项目《谷粒商城》架构师级Java项目实战&#xff0c;对标阿里P6-P7&#xff0c;全网最强 总时长 104:45:00 共408P 此文章包含第158p-第p165的内容 分布式锁 原理和使用 使用下shell对产生的命令进行发送 查看 -> 撰写 -> 撰写栏 idea 选中的代码提取成方法 加锁…

使用tcpdump和wireshark进行服务器抓包分析

目录 前言 1.tcpdump简介 2.Wireshark简介 3.实际案例 4.代码示例 5.总结 前言 服务器抓包分析是一种非常常见和有效的网络故障排查和性能优化手段。通过捕获服务器上的网络流量&#xff0c;可以帮助我们深入了解服务器与其它设备之间的通信情况&#xff0c;发现问题并进…

基于8086贪吃蛇游戏系统方恨设计

**单片机设计介绍&#xff0c;基于8086贪吃蛇游戏系统方恨设计 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于8086的贪吃蛇游戏系统设计是一个结合了微处理器控制、游戏逻辑以及图形显示技术的综合性项目。该系统旨在通过8086微处理器…

JAVA----线程

线程 上回说到 进程 > 运行起来的程序 > 并发编程 > 多核 CPU 操作系统管理进程: 先描述 > PCB 结构体 来把进程的各种属性都表示出来再组织 > 通过链表数据结构把多个 PCB 串起来. PCB 核心属性(进程调度) pid 进程标识符内存指针, 该进程依赖的 指令…

NIKKI DENSO伺服驱动器维修NCR-CAB1A2D-801B

NEXSRT伺服驱动器维修NPSA-MU日机电装伺服维修ACTUS POWER&#xff0c;NCS-ZE12MDA/ZE1MDA-601A&#xff0c;NEXSRT日机电装伺服维修NCS-ZE12MDB-401A/NCS-ZAMDA-401AG。 NIKKI常见故障原因及处理方法&#xff1a; 1、电机在一个方向上比另一个方向跑得快&#xff1b; (1) 故…

Keil MDK 5.37 及之后版本 安装 AC5(ARMCC) 编译器详细步骤

由于 Keil 5.37 及之后版本不再默认安装 AC5(ARMCC) 编译器&#xff0c;这就会导致由 AC5 编译的工程无法正常编译&#xff0c;往往输出窗口会提示以下信息&#xff1a;*** Target ‘STM32xxxx‘ uses ARM-Compiler ‘Default Compiler Version 5‘ which is not available. —…

Redis数据库:概念、安装及常用操作命令

目录 前言 一、数据库概述 1、关系型数据库&#xff08;RDBMS&#xff09; 1.1 产生背景 1.2 概念 1.3 特点 1.4 优缺点 1.5 常见主流关系型数据库 2、非关系型数据库&#xff08;NoSQL&#xff09; 2.1 产生背景 2.2 概念 2.3 特点 2.4 优缺点 2.5 常见主流非关…

实验三 Java类的继承与派生(计算机专业)

实验三 Java类的继承与派生&#xff08;头歌&#xff09; 制作不容易&#xff0c;点个关注&#xff01;给大家带来更多的价值&#xff01; 目录 实验三 Java类的继承与派生&#xff08;头歌&#xff09;** 制作不容易&#xff0c;点个关注&#xff01;给大家带来更多的价值&…

HBase(超级无敌详细PROMAX讲解版)

简介 概述 图-1 HBase图标 HBase原本是由Yahoo!公司开发的后来贡献给了Apache的一套开源的、基于Hadoop的、分布式的、可扩展的非关系型数据库(Non-Relational Database)&#xff0c;因此HBase不支持SQL(非关系型数据库基本上都不支持SQL)&#xff0c;而是提供了一套单独的命…

文件搜索案列 --java

目标&#xff1a; 搜索盘符下面符合要求的文件名&#xff0c;并可以选择是否打开该文件 代码&#xff1a; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Scanner;public class findQQ {public static void main(String[] a…

Node.js-------初识Node.js与内置模块

能够知道什么是 Node.js能够知道 Node.js 可以做什么能够说出 Node.js 中的 JavaScript 的组成部分能够使用 fs 模块读写操作文件能够使用 path 模块处理路径能够使用 http 模块写一个基本的 web 服务器 一.初识Node.js 1.浏览器中的 JavaScript 的组成部分 2.Node.js 简介 …