树的前中后序遍历-非递归的迭代写法

news2024/12/28 21:52:28

就是要我们非递归其实就是模仿递归的写法,类如递归一样遍历一棵树,但是却不是递归的写法,

防止栈溢出。

二叉树的前序遍历

先看递归代码:

void _preorderTraversal(TreeNode* root,vector<int>&v)
{
    if (root == NULL)
	{
		return;
	}
	v.push_back(root->val);
	preorderTraversal(root->_left);
	preorderTraversal(root->_right);
}


vector<int> preorderTraversal(TreeNode* root)
{
    vector<int> v;
     _preorderTraversal(root,v);
    return v;
}

        递归遍历访问到nullptr时,可以返回上一层结点,再去访问右子树。这里我们是在上一级栈帧中保存了直系父节点才做到,当该父节点结束以后代表他的左右结点都访问完毕,然后再返回他的上一层结点(B的左右结点访问完毕,返回到A,再去访问C)为什么能再次返回呢?因为每一层栈帧保存了一个父节点。我们的非递归就是要做到这样的情况。类似栈帧的完成方法实现,这就要使用到我们的栈了。

我们规定了遍历顺序都是先遍历左子树再遍历右子树,所以我们的前序遍历就要先访问左子树

 每到一个非空树时就要将根结点保存在栈中.然后继续访问左子树cur=cur->left

 

当访问到左树为空时就将栈顶元素拿出来并且删除栈顶元素,将拿出的二叉树根指针的右子树赋值给遍历指针

 cur遇nullptr时继续取栈顶元素并删除栈顶,右树继续赋值给cur

然后压入元素E,cur=cur->left

cur==nullptr结束循环,取栈顶元素,将元素的右树赋值给cur,并pop栈。  

cur==nullptr结束循环,取栈顶元素,将元素的右树赋值给cur,并pop栈。  

 最后访问结束后cur==nullptr,stack也是空栈。

 

访问结束,退出循环。

查看代码:

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> v;
        TreeNode*cur=root;
        //只有栈空并且cur==nullptr才会退出循环。
        while(cur ||!st.empty())
        {
            将节点访问,并且移动到左子树
            while(cur)
            {
                //入vector就是对结点访问。
                v.push_back(cur->val);
                st.push(cur);
                cur=cur->left;
            }
            cur=st.top()->right;
            st.pop();
        }
        return v;
    }
};

中序遍历

中序遍历的迭代写法类似于前序迭代代码。改变访问位置即可,前序遍历都是来到一个结点先访问在去左子树,而中序就是子树访问完毕后再去访问根结点。在栈top时访问该元素即可。

看中序代码:

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();
            //取出栈顶元素后访问就是中序访问
            v.push_back(top->val);
            //访问后将top的右子树赋值给cur
            cur=top->right;
            st.pop();
        }
        return v;
    }
};

后序遍历(重点)

画图+代码理解。

    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;
            }
         //......

前面代码和中序遍历一样,但是我们加了一个prev指针,用来保存返回前的结点

当我们访问到cur==nullptr是取栈顶元素进行操作。

 

auto top=st.top();
if(top->right==nullptr||top->right==prev)
{
    v.push_back(top->val);
    prev=top;
    st.pop();
}
else
{
    cur=top->right;
}

 top->right==nullptr:当我们的结点的左边访问完毕后查看右边是否为空如果为空,就表示对结点数据访问。

top->right==prev:prev保存取出上一层取出栈顶的元素,我们查看他是否为这次栈顶结点的右结点,如果等于就意味着该节点的右子树访问完毕。

有点抽象吧?画个图,我也活动以下脑子。

 

 

 

 

 此刻!!大循环判断不成立退出循环

结束循环返回数据。树以后序遍历结束!!!

完整代码:

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;
            }
            auto top=st.top();
        if(top->right==nullptr||top->right==prev)
        {
            v.push_back(top->val);
            prev=top;
            st.pop();
        }
        else
        {
            cur=top->right;
        }
        }
        return v;
    }
};

 

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

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

相关文章

C语言 结构体入门

目录 一、定义和使用结构体变量 1.1创建结构体类型 1.2定义结构体类型变量 1.先声明结构体类型&#xff0c;在定义该类型的变量 2.在声明类型的同时定义 1.3结构体成员的类型 1.4结构体变量的初始化和引用 1.5结构体的访问 二、结构体传参 前言&#xff1a;C语言提供…

直流稳压电源的几个性能指标

目录 电压调整率&#xff1a;输入电压在允许的范围内变化时&#xff0c;输出电压稳定性。 电流调整率&#xff1a;负载电流在允许的范围内变化时&#xff0c;输出电压稳定性 输出纹波电压&#xff1a;额定负载时&#xff0c;输出电压的振幅 电源效率&#xff1a;额定负载时&…

07-抚摸抽象边界:Golang 接口的多彩展现

&#x1f4c3;个人主页&#xff1a;个人主页 &#x1f525;系列专栏&#xff1a;Golang基础 &#x1f4ac;Go&#xff08;又称Golang&#xff09;是由Google开发的开源编程语言。它结合了静态类型的安全性和动态语言的灵活性&#xff0c;拥有高效的并发编程能力和简洁的语法。G…

Python 操作 Excel 全攻略 | 包括读取、写入、表格操作、图像输出和字体设置

文章目录 前言Python 操作 Excel 教程1. Excel 文件的读取与写入2. Excel 表格的操作2.1 插入和删除行和列2.2 遍历表格中的单元格并修改值 3. 图像的输出3.1 输出柱状图 4. 字体的设置4.1 设置单元格的字体大小和颜色4.2 设置单元格的加粗和斜体4.3 设置单元格的边框和填充颜色…

android实现无root获取其它应用data私有数据

实现原理就是反编译app的AndroidManifest文件&#xff0c;注意是反编译应用的资源文件&#xff0c;而不是编译整个app&#xff0c;这个操作不需要动应用的dex&#xff0c;难度上要容易得多。解码资源文件要用到一些工具&#xff0c;android下推荐ARSCLib。接下来是对目标应用重…

04_Linux设备树DTB文件OF函数

目录 创建小型模板设备树 添加cpus节点 添加soc节点 添加ocram节点 添加aips1、aips2和aips3这三个子节点 添加eespil、usbotg1和rngb这三个外设控制器节点 设备树在系统中的体现 根节点“/”各个属性 根节点“/”各子节点 特殊节点 aliases子节点 chosen子节点 L…

转专业之我见

写在前面 如果你点进来看这篇文章&#xff0c;说明你的至少有想转专业的想法甚至心里是趋向于转专业的。 但是或许是因为学校只有一次转专业的机会或者有别的原因让你犹豫不决&#xff0c;那么你首先要明确你为什么想要转专业&#xff0c;是因为本专业是天坑专业&#xff0c;…

UI 自动化测试 —— selenium的简单介绍和使用

selenium 是 web 应用中基于 UI 的自动化测试框架&#xff0c;支持多平台、多浏览器、多语言。 提到 UI 自动化就先了解什么是自动化测试&#xff1f; 目录 1. 自动化测试 2. UI 自动化 2.1 UI 自动化的特点 2.2 UI 自动化测试的优缺点 2.3 UI 自动化测试的使用对象 2.4…

PPG信号和ECG信号检测血管年龄

PAT 通常用作动脉硬度的间接测量值或心血管健康的指标。它与各种生理和病理状况有关&#xff0c;例如高血压、动脉硬化和内皮功能障碍。 通过脉搏到达时间进行测量&#xff0c;简单来说就是 先从脉冲传输时间 PPG 数据集中提取数据&#xff0c;提取此数据集中每个对象的脉冲到…

【Python从入门到进阶】24、urllib获取网站电影排行

接上篇《23、urllib使用post请求百度翻译》 上一篇我们讲解了如何使用urllib实现百度翻译的效果。本篇我们来讲解如何使用urllib抓取某某电影排行榜信息。 一、某某电影介绍 1、某某电影网站 某某电影成立于2005年&#xff0c;最初只是一个小型的电影社区&#xff0c;但随着…

【备战秋招】每日一题:2023.05-B卷-华为OD机试 - 报文重排序

为了更好的阅读体检&#xff0c;可以查看我的算法学习博客报文重排序 题目描述 对报文进行重传和重排序是常用的可靠性机制&#xff0c;重传缓中区内有一定数量的子报文&#xff0c;每个子报文在原始报文中的顺序已知&#xff0c;现在需要恢复出原始报文。 输入描述 输入第…

改进YOLOv8 | 优化器篇 | YOLOv8 引入谷歌 Lion 优化器

论文地址:https://arxiv.org/pdf/2302.06675.pdf 代码地址:https://github.com/google/automl/tree/master/lion 我们提出了一种将算法发现作为程序搜索的方法,并将其应用于发现用于深度神经网络训练的优化算法。我们利用高效的搜索技术来探索一个无限且稀疏的程序空间。为了…

【SCADA】测试用KingIOServer采集杰控OPC DA服务器数据

Hello&#xff0c;大家好&#xff0c;我是雷工&#xff01; 现场做数据采集时经常会遇到需要通过OPC采集数据的情况&#xff0c;本篇测试KingIOServer采集北京杰控组态软件的OPCDA服务器数据。 以下为测试记录过程。 一、KingIOServer的OPC DA数据采集介绍 KingIOServer可以作…

Vue中如何进行分布式日志管理与日志分析

Vue中如何进行分布式日志管理与日志分析 在现代应用程序中&#xff0c;日志是一项重要的功能&#xff0c;用于帮助开发人员和运维人员了解应用程序的行为并进行故障排除。随着应用程序的规模和复杂性的增加&#xff0c;日志管理和分析变得越来越困难。本文将介绍如何在Vue应用…

JSON对象花样进阶

JSON 对象使用在大括号{ }中书写。 对象可以包含多个 key/value&#xff08;键/值&#xff09;对。 key 必须是字符串&#xff0c;value 可以是合法的 JSON 数据类型&#xff08;字符串, 数字, 对象, 数组, 布尔值或 null&#xff09;。 key 和 value 中使用冒号(:)分割。 每个…

Postman接口自动化之postman脚本编写

这是之前搞的接口自动化方案&#xff0c;已经在业务测试中实现了使用postman编写接口脚本&#xff0c;通过GitHubJenkinsemail html report实现了接口自动化&#xff0c;现在分块整理一下。 postman脚本编写 1、创建集合 和 目录&#xff1a; 一条业务线下的接口可以放到一个…

ACL2023 | 大模型如何快速构建指令遵循数据集?self-instruct:用175条种子数据追上InstructGPT001效果

一、概述 title&#xff1a;SELF-INSTRUCT: Aligning Language Models with Self-Generated Instructions 论文地址&#xff1a;https://arxiv.org/abs/2212.10560 代码&#xff1a;GitHub - yizhongw/self-instruct: Aligning pretrained language models with instruction…

chatgpt赋能python:Python怎么输出Unicode值

Python怎么输出Unicode值 Python 是一种高级编程语言&#xff0c;因其简单易学和快速开发已成为许多开发者的首选。Python 可以输出多种数据类型&#xff0c;包括字符串和数字。 在许多情况下&#xff0c;输出 Unicode 值是必需的&#xff0c;本文将介绍在 Python 中如何输出 …

shardingsphere第二课-shardingsphere-jdbc的基本使用及各种分片策略

第一章介绍 一、ShardingJDBC客户端分库分表 ShardingSphere-JDBC 定位为轻量级 Java 框架&#xff0c;在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库&#xff0c;以 jar 包形式提供服务&#xff0c;无需额外部署和依赖&#xff0c;可理解为增强版的 JDBC 驱动…

chatgpt赋能python:Python中如何输入一个列表

Python中如何输入一个列表 输入一个列表是Python编程的基本任务之一。列表可以看做是一种序列&#xff0c;其中包含多个元素&#xff0c;用逗号隔开&#xff0c;并用方括号括起来。在Python中&#xff0c;列表是一种非常常见的数据类型&#xff0c;常用于存储和处理一系列相关…