算法力扣刷题 三十六【二叉树迭代遍历】

前言

记录三十五 介绍了二叉树基础,和递归法模版及遍历方式;
递归:代码简单,但要想清楚三步:

  • 确定参数和返回值;
  • 确定终止条件,并return什么?;
  • 终止条件外的逻辑,在哪里做到自己调用自己?——应该是出现嵌套时候,要重复操作的时候。

递归的问题:递归次数多,开的新栈多,内存空间占用大。

如果二叉树前中后序遍历使用非递归方法,怎么操作?


一、“输入”学习阶段

学习参考链接

解释迭代

重复执行一段代码,直到满足某个条件后停止。用循环可以实现重复;(递归也是重复)。

前序遍历

过程

模拟递归过程,用结构栈。

  • 先把根节点放到栈中,再取出根节点加入遍历数组;
  • 先放入右孩子,再放入左孩子。(左孩子先出来,说明先处理左子树)。
  • 直到栈为空。
  • 总结:取出根节点,拿右孩子和左孩子入栈交换。先访问到中节点,可以直接处理中节点;再访问到左孩子(后入栈),处理左子树;再访问到右孩子(先入栈),处理右子树。访问节点顺序=处理节点顺序

代码实现

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:vector<int> preorderTraversal(TreeNode* root) {vector<int> result;stack<TreeNode*> st;st.push(root);while(!st.empty()){TreeNode* cur = st.top();st.pop();if(cur != nullptr){result.push_back(cur->val);st.push(cur->right);	//如果cur是叶子节点,把空也入栈,但是取到空的时候不操作。st.push(cur->left);}}return result;}
};

上面的实现:把叶子结点的左右孩子是空,也入栈,但是不操作。

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:vector<int> preorderTraversal(TreeNode* root) {vector<int> result;stack<TreeNode*> st;if(root == nullptr) return result;st.push(root);while(!st.empty()){TreeNode* 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;}
};

这是参考代码,空就不入栈,所以可以在pop之后直接push_back。

后序遍历

过程

  • 前序实现得到:中左右;
  • 如果先放左孩子,再放右孩子;得到中右左;
  • 把result最后整体reverse,得到左右中。
  • 总结:先访问到中节点,可以直接处理中节点;再访问到右孩子(后入栈),处理右子树;再访问到左孩子(先入栈),处理左子树。访问节点顺序=处理节点顺序。最后reverse结果。

代码实现

参考代码:

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:vector<int> postorderTraversal(TreeNode* root) {vector<int> result;stack<TreeNode* > st;if(root == nullptr) return result;st.push(root);while(!st.empty()){TreeNode* cur = st.top();st.pop();result.push_back(cur->val);if(cur->left) st.push(cur->left);if(cur->right) st.push(cur->right);}reverse(result.begin(),result.end());return result;}
};

中序遍历

过程

有所区别原因:访问节点顺序不等于处理节点顺序。每一次先接触中间节点,但不能处理它,要找它的左子树;找到左子树,再处理它;再找右子树。

  • 用栈来记录遍历过的元素,虽然访问到但是还没到要处理的时候。
  • cur != 空,作为中节点,放入栈中;cur = cur->left;把left给到下一棒。
  • 如果遇到空,说明左子树结束;需要从栈中取元素,放入result,st.pop();cur = cur->right;再把right给到下一棒。
  • 当cur == 空且st栈为空,终止。cur==空,说明访问结束;st等于空,说明没有中节点可以取。

代码实现

  • 根据思路,先自我实现:
    /*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
    class Solution {
    public:vector<int> inorderTraversal(TreeNode* root) {vector<int> result;stack<TreeNode*> st;if(root == nullptr) return result;st.push(root);TreeNode* cur = root->left;while(1){if(cur != nullptr){st.push(cur);cur = cur->left;}else{if(st.empty()) break;cur = st.top();st.pop();result.push_back(cur->val);cur = cur->right;}}return result;}
    };
    
  • 对照参考代码:
    去掉 if(st.empty()) break; while条件改为(cur != nullptr || !st.empty())

二、统一迭代遍历实现

学习参考链接

思路学习

标记法

  • 访问的节点放入栈中,把要处理的节点也放入栈中但是标记要处理的节点。
  • 如何标记?要处理的节点放入栈之后,紧接着放入一个空指针作为标记

代码实现

  • 前序遍历:中左右。所以cur不为空时,入栈顺序:右左中。
/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:vector<int> preorderTraversal(TreeNode* root) {vector<int> result;stack<TreeNode*> st;if(root != nullptr) {st.push(root);}while(!st.empty()){TreeNode* cur = st.top();if(cur != nullptr){st.pop();if(cur->right) st.push(cur->right);//先放入右孩子if(cur->left) st.push(cur->left); //再放入左孩子st.push(cur);   //放入中节点,紧跟着NULL,代表处理过,它下一轮该进resultst.push(nullptr);}else{st.pop();   //把空指针先弹出TreeNode* temp = st.top();//获取入数组的元素st.pop();   //弹出该元素result.push_back(temp->val); }}return result;}
};
  • 中序遍历:左中右。所以cur不为空时,入栈顺序:右中左。
/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:vector<int> preorderTraversal(TreeNode* root) {vector<int> result;stack<TreeNode*> st;if(root != nullptr) {st.push(root);}while(!st.empty()){TreeNode* cur = st.top();if(cur != nullptr){st.pop();if(cur->right) st.push(cur->right);//先放入右孩子st.push(cur);   //放入中节点,紧跟着NULL,代表处理过,它下一轮该进resultst.push(nullptr);if(cur->left) st.push(cur->left); //再放入左孩子}else{st.pop();   //把空指针先弹出TreeNode* temp = st.top();//获取入数组的元素st.pop();   //弹出该元素result.push_back(temp->val); }}return result;}
};
  • 后序遍历:左右中。所以cur不为空时,入栈顺序:中右左。
/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:vector<int> postorderTraversal(TreeNode* root) {vector<int> result;stack<TreeNode*> st;if(root != nullptr) st.push(root);while(!st.empty()){TreeNode* cur = st.top();if(cur != nullptr){st.push(nullptr);	//先放中节点,直接放null,标记下if(cur->right) st.push(cur->right);//再放右孩子if(cur->left) st.push(cur->left);//再放左孩子}else{st.pop();TreeNode* temp = st.top();st.pop();result.push_back(temp->val);}}return result;}
};

总结

本文学习迭代遍历二叉树。用循环+栈处理。

  • 非统一的方法:
    • 前序遍历:根节点先入栈,每出栈一个根节点,就把右左孩子放入。相当于交换。
    • 后序遍历:中左右——中右左——左右中;
    • 中序遍历:栈放遍历的元素,不为空,把left交到下一棒;为空,取出中节点;把right交到下一棒。
  • 统一方法:标记法。要处理的节点后面紧跟着是null,取到栈顶是空,代表要入栈。直到整个栈空。
    • 前序遍历:不为空,放入顺序:右左中;
    • 中序遍历:不为空,放入顺序:右中左;
    • 后序遍历:不为空,放入顺序:中右左;

(欢迎指正,转载标明出处)

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

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

相关文章

【AI大模型】赋能儿童安全:楼层与室内定位实践与未来发展

文章目录 引言第一章&#xff1a;AI与室内定位技术1.1 AI技术概述1.2 室内定位技术概述1.3 楼层定位的挑战与解决方案 第二章&#xff1a;儿童定位与安全监控的需求2.1 儿童安全问题的现状2.2 智能穿戴设备的兴起 第三章&#xff1a;技术实现细节3.1 硬件设计与选择传感器选择与…

SpringSecurity中文文档(Servlet Authorization Architecture )

Authorization 在确定了用户将如何进行身份验证之后&#xff0c;还需要配置应用程序的授权规则。 Spring Security 中的高级授权功能是其受欢迎的最有说服力的原因之一。无论您选择如何进行身份验证(无论是使用 Spring Security 提供的机制和提供者&#xff0c;还是与容器或其…

两张图片合并(右上角添加水印,兼容矢量图)保留原来的颜色

无缝合并两张图片&#xff08;封面右上角添加logo&#xff09;-- opencv &#xff1a; 进行添加logo(水印)由于使用了cv2.seamlessClone&#xff0c;cv2.seamlessClone使用了泊松克隆&#xff08;Poisson Cloning&#xff09;&#xff0c;会根据周围的颜色信息进行颜色调整&…

tcp并发设计

4注意&#xff1a;原始代码&#xff0c;如果先关闭服务器端&#xff0c;再次开启服务器的时候会报"connect: Connection refused "错误&#xff0c;这是因为先关服务器端&#xff0c;导致系统认为客户端仍然在与服务器端连接造成。 可以使用setsockopt setsockopt函…

three-tile 一个开源的轻量级三维瓦片库

three-tile 介绍 three-tile 是一个开源的轻量级三维瓦片库&#xff0c;它基于threejs使用typescript开发&#xff0c;提供一个三维地形模型&#xff0c;能轻松给你的应用增加三维瓦片地图。 源码&#xff1a;https://github.com/sxguojf/three-tile 示例&#xff1a;https:/…

【TB作品】51单片机 Proteus仿真 00013红外proteus仿真循迹避障小车

实验报告&#xff1a;智能小车系统设计与实现 一、背景介绍 本实验旨在设计并实现一个基于STC89C52单片机控制的智能小车系统。该系统通过超声波传感器进行避障&#xff0c;通过红外接收器实现远程控制&#xff0c;同时具备循迹功能。整个系统的核心是单片机&#xff0c;它通…

YOLOv10改进 | 损失函数篇 | InnerIoU、InnerSIoU、InnerWIoU、FocusIoU等损失函数

一、本文介绍 本文给大家带来的是YOLOv10最新改进&#xff0c;为大家带来最近新提出的InnerIoU的内容同时用Inner的思想结合SIoU、WIoU、GIoU、DIoU、EIOU、CIoU等损失函数&#xff0c;形成 InnerIoU、InnerSIoU、InnerWIoU、等新版本损失函数&#xff0c;同时还结合了Focus和…

LeetCode42(接雨水)[三种解法:理解动态规划,双指针,单调栈]

接雨水 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 这是一道困难题,难度确实有点层次.我们先来朴素思想走一波. 要求能接多少雨水,我们可以具化到每个硅谷,每个硅谷能存多少雨水,那么答案就是每个…

PDA:Prompt-based Distribution Alignment for Unsupervised Domain Adaptation

文章汇总 式中&#xff0c; y s y^s ys表示源域数据的one-hot ground-truth&#xff0c; K K K为类数&#xff0c; w i w_i wi​和 z ~ s \tilde{z}_s z~s​分别表示源域经过提示调优的最终文本表示和最终图像表示的第 i i i类。 同理&#xff0c;为了进一步利用目标领域的数据…

防火墙详解(USG6000V)

0、防火墙组网模式 防火墙能够工作在三种模式下分别是路由模式、透明模式、旁路检测模式、混合模式 0.1、路由模式 路由模式&#xff1a;防火墙全部以第三层对外连接&#xff0c;即接口具有IP 地址。一般都用在防火墙是边界的场景下 防火墙需要的部署/配置&#xff1a; 接…

【入门篇】STM32寻址范围(更新中)

写在前面 STM32的寻址范围涉及存储器映射和32位地址线的使用。并且STM32的内存地址访问是按字节编址的,即每个存储单元是1字节(8位)。 一、寻址大小与范围 地址线根数 地址编号(二进制) 地址编号数(即内存大小) <

实现基于Elasticsearch的搜索服务

实现基于Elasticsearch的搜索服务 大家好&#xff0c;我是微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 1. Elasticsearch简介 Elasticsearch是一个开源的分布式搜索引擎&#xff0c;提供强大的全文搜索和分析功能。本文…

10、DDD分层架构

微服务架构模型有很多种&#xff0c;例如洋葱架构、CQRS和六边形架构等。虽然这些架构模式提出的时代和背景不同&#xff0c;但其核心理念都是为了设计出“高内聚&#xff0c;低耦合”的微服务&#xff0c;轻松实现微服务的架构演进。DDD分层架构的出现&#xff0c;使微服务的架…

什么是ThreadLocal以及内存泄漏问题、hash冲突问题

ThreadLocal是什么 ThreadLocal类用来提供线程内部的局部变量 它主要有三大特性&#xff1a; 线程安全: 在多线程并发的场景下保证线程安全传递数据&#xff1a;通过ThreadLocal在同一线程传递公共变量线程隔离&#xff1a;每个线程的变量都是独立的&#xff0c;不会互相影响…

这次让我们从几个点认识一下Mysql的Innodb

MySQL 的 InnoDB 存储引擎是 MySQL 默认和最常用的存储引擎之一。它主要关注的是高可靠性、性能以及完整的事务支持。以下是对 InnoDB 存储引擎的详细介绍&#xff1a; 1. 数据库特性 1.1 事务支持 InnoDB 是完全支持事务的存储引擎&#xff0c;支持四种主要的事务隔离级别&…

【uniapp-ios】App端与webview端相互通信的方法以及注意事项

前言 在开发中&#xff0c;使用uniapp开发的项目开发效率是极高的&#xff0c;使用一套代码就能够同时在多端上线&#xff0c;像笔者之前写过的使用Flutter端和webview端之间的相互通信方法和问题&#xff0c;这种方式本质上实际上是h5和h5之间的通信&#xff0c;网上有非常多…

ios身份证实名认证接口开发示例助力电商物流实名认证

为了更好的利用货车资源&#xff0c;也方便企业正常的运送货物&#xff0c;“互联网电商”平台可谓风起云涌。货车司机和有发货需求的人们可以在物流平台注册&#xff0c;货车司机接单为有运送需求的用户提供有偿货运服务。那么&#xff0c;如何让企业放心的将货物安心的交予货…

物联网实训室建设可行性报告

一、建设物联网实训室的目的和意义 随着信息技术的快速发展&#xff0c;物联网&#xff08;IoT&#xff09;已成为推动社会进步和经济发展的关键技术之一。物联网技术的集成应用&#xff0c;不仅能够提高生产效率&#xff0c;还能促进智慧城市、智能家居、智能农业等多个领域的…

python04——类(基础new)

类其实也是一种封装的思想&#xff0c;类就是把变量、方法等封装在一起&#xff0c;然后可以通过不同的实例化对其进行调用操作。 1.类的定义 class 类名&#xff1a; 变量a def __init__ (self,参数2&#xff0c;参数2...)&#xff1a;初始化函数&#xff01;&#xff01;&…

vivado DELAY_VALUE_XPHY、DIFF_TERM

延迟_值_XPHY PORT对象上的DELAY_VALUE_XPHY属性指定要添加的延迟量 Versal XPHY逻辑接口的输入或输出路径。在的早期阶段 opt_design在重新生成高级I/O向导IP时 DELAY_VALUE_XPHY值将从PORT复制到的XPHY实例上 输入或输出路径。Vivado设计套件中存在DRCs&#xff0c;以确保 DE…