力扣145题:二叉树的后序遍历

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 

示例 1:

输入:root = [1,null,2,3]
输出:[3,2,1]

示例 2:

输入:root = []
输出:[]

示例 3:

输入:root = [1]
输出:[1]

提示:

  • 树中节点的数目在范围 [0, 100] 内
  • -100 <= Node.val <= 100

【方法一】递归算法

二叉树的后序遍历按照:左-右-根来进行。

针对主函数,我们需要定义一个数组a,将遍历的树中元素放在数组中;returnSize指针所指向的值初始化为0,表示结果数组的大小初始为0;调用postorder函数,返回数组a。

针对调用函数,首先进行判断是否为空,为空的话直接进行返回,不需要进行任何操作。然后按照左-右-根来进行遍历。针对根节点处理:a[(*returnSize)++]=root->val。

具体案例分析

root = [1,null,2,3],输出:[3,2,1]。

针对主函数,开始时a[0]={},returnSize=0,调用postorder(root->left, a, returnSize),为空直接返回。进行调用postorder(root->right, a, returnSize)。由于root=2不为空,则继续进行调用postorder(root->left, a, returnSize)和postorder(root->right, a, returnSize)。

针对调用postorder(root->left, a, returnSize),此时root=3,进行调用,发现左和右均为空,则将3添加到数组a[0]中,并将 *returnSize 递增为1。然后返回到根为2时进行调用postorder(root->right, a, returnSize),为空,则将2添加到数组a[1]中,并将 *returnSize 递增为1。

此时到达最外层循环,也就是roo=1时,左为空,右已经调用完,则将1添加到数组a[2]中,并将 *returnSize 递增为1。

最终,数组 a 包含元素 [1, 2, 3],并且 *returnSize 为3。

返回数组 a。

(整个流程可以描述为,root=1->postorder(root->left, a, returnSize)为空->调用postorder(root->right, a, returnSize),此时root=2->调用postorder(root->left, a, returnSize)和postorder(root->right, a, returnSize)->首先针对postorder(root->left, a, returnSize),root=3,左右均空,将root=3加入到数组中->然后针对postorder(root->right, a, returnSize),root=2->right为空,则直接将2加入数组中->返回到最外层循环,将1加入到数组中->返回a[1,2,3]。

C语言具体代码如下:

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     struct TreeNode *left;*     struct TreeNode *right;* };*/
/*** Note: The returned array must be malloced, assume caller calls free().*/void postorder(struct TreeNode* root, int* a, int* returnSize) {if (!root) {  //树是空return;}postorder(root->left, a, returnSize);postorder(root->right, a, returnSize);a[(*returnSize)++] = root->val;  
}int* postorderTraversal(struct TreeNode* root, int* returnSize) {int* a = malloc(sizeof(int) * 100);*returnSize = 0; postorder(root, a, returnSize);return a;  
}

时间复杂度O(n);空间复杂度O(n)

【方法一】迭代算法

二叉树的后序遍历按照:左-右-根来进行。

后序遍历中,要保证左孩子和右孩子都已经被访问并且左孩子在右孩子前访问才能访问根节点。可通过辅助指针q来进行标记上一个访问的节点。

第一步创建一个栈。

第二步:定义一个stack来开辟一个栈空间,并将栈初始化,top=0。定义一个数组,用来返回最后后续遍历后的树,returnSize指针的值初始化为0,定义一个指针p来指向树的根,定义一个指针q指向空,用来标记上一个访问的节点。

第三步:当p不为空或者top不指在栈顶的时候,进判断。如果p不为空,stack->s[stack->top] = p,并将top++,进行移动,并将p指向左孩子。如果p为空的时候,p=stack->s[stack->top],然后进行判断p的右孩子是否为空或者为q。将栈中的元素给数组,并将q标记在p这个位置,然后将top--,并将p指向空。如果if语句不满足,直接将p指向右孩子。最后返回数组。

具体案例分析

root = [1,null,2,3],输出:[3,2,1]。

开始时:p=1,top=0,stack->s[0]=p=1,top++为1,将p指向左孩子为空。则,此时p=NULL。

p=NULL,执行else里面的语句。p=stack[1-1=0]=1,执行else 中if语句,不符合,则执行else中if中的else语句,p=p->right=2。则,此时p=2。

p=2,不为空,进行if (p != NULL)遇见,stack->s[1]=p=2(此时栈中1,2),top++为2,将p指向左孩子为3。则,p=3。

p=3,不为空,进行if (p != NULL)遇见,stack->s[2]=p=3(此时栈中1,2,3),top++为3,将p指向左孩子空。则,p=NULL。

p=NULL,执行else里面的语句。p=stack[3-1=2]=3,执行else 中if语句,符合,则a[0]={3},returnSize=1,q=3,top=2,p=NULL。

p=NULL,执行else里面的语句。p=stack[2-1=1]=2,执行else 中if语句,符合,则a[1]={3,2},returnSize=2,q=2,top=1,p=NULL。

p=NULL,执行else里面的语句。p=stack[1-1=0]=1,执行else 中if语句,符合,则a[2]={3,2,1},returnSize=3,q=1,top=0,p=NULL。

top=0,p=NULL,不符合while循环,跳出,返回a[2]={3,2,1}。

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     struct TreeNode *left;*     struct TreeNode *right;* };*/
/*** Note: The returned array must be malloced, assume caller calls free().*/
struct stack {struct TreeNode *s[100];int top;
};// 后序遍历函数
int* postorderTraversal(struct TreeNode* root, int* returnSize) {struct stack *stack = (struct stack *)malloc(sizeof(struct stack));stack->top = 0;int *a = (int *)malloc(sizeof(int) * 100);*returnSize = 0;struct TreeNode *p = root;struct TreeNode *q = NULL; // 用于记录上一次访问的节点while (p != NULL || stack->top != 0) {if (p != NULL) {stack->s[stack->top] = p;(stack->top)++;p = p->left;} else {p = stack->s[stack->top - 1];if (p->right == NULL || p->right == q) {a[(*returnSize)++] = p->val;q = p;(stack->top)--;p = NULL;} else {p = p->right;}}}return a;
}

时间复杂度O(n);空间复杂度O(n)

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

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

相关文章

C++复习的长文指南

C复习的长文指南 一、入门语法知识1.预备1.1 main函数1.2 注释1.3 变量1.3 常量1.4 关键字1.5 标识符明明规则 2. 数据类型2.1 整型2.1.1 sizeof关键字 2.2 实型&#xff08;浮点型&#xff09;2.3 字符型2.4 转义字符2.5 字符串型2.6 布尔类型bool2.7 数据的输入 3. 运算符3.1…

C语言 default 踩坑

void fun(char c) {switch(c){case b :cout << "ttt" << endl;break;defualt:cout << "test" <<endl;} }这段代码中&#xff0c;理论上来说&#xff0c;当cb’时应该打印 “ttt”&#xff0c;否则&#xff0c;应该打印 “test”。…

WHAT - 介绍一个不太一样的 UI 组件库 shadcn/ui

目录 一、介绍主要特点核心组件示例代码社区和支持总结 二、copy/paste1. 高度可定制性2. 避免依赖锁定3. 学习和理解4. 简化调试5. 项目需求变化 官方文档&#xff1a;https://ui.shadcn.com/docs 一、介绍 ShadCN (ShadCN/UI) 是一个现代的 React 组件库&#xff0c;旨在提…

SwiftUI 6.0(Xcode 16)新 PreviewModifier 协议让预览调试如虎添翼

概览 用 SwiftUI 框架开发过应用的小伙伴们都知道&#xff0c;SwiftUI 中的视图由各种属性和绑定“扑朔迷离”的缠绕在一起&#xff0c;自成体系。 想要在 Xcode 预览中泰然处之的调试 SwiftUI 视图有时并不是件容易的事。其中&#xff0c;最让人秃头码农们头疼的恐怕就要数如…

对redis进行深入学习

目录 1. 什么是redis&#xff1f;1.1 为什么使用redis作为缓存&#xff1f;1.1.0 数据库&#xff08;MySQL&#xff09;与 redis1. 存储介质不同&#xff08;408选手应该都懂hh&#xff09;2. 数据结构优化3. I/O模型差异4. CPU缓存友好性5. 单线程与多线程差异6. 持久化与缓存…

Postcat使用全解析

文章目录 引言官网链接Postcat原理概述基础使用安装与启动创建与发送请求环境变量 高级使用集合与预请求脚本代码生成器 优缺点分析优点缺点 结论 引言 Postcat&#xff0c;作为一款功能丰富的API开发与测试工具&#xff0c;受到了广大开发者的喜爱。它提供了直观的用户界面和…

C语言 二叉树,一个猜动物的小游戏

1. 此项目用到的知识点: 二叉树&#xff0c; struct&#xff0c; 文件读写。 2. 其中最复杂的地方是&#xff1a;复制一个指针的内容&#xff0c;参考&#xff1a;https://stackoverflow.com/questions/39938648/copy-one-pointer-content-to-another 1. 头文件 "node_ut…

进程的地址空间

一、写个代码见一见地址空间 1、问题 在代码中我们在第五秒时会在子进程中改变全局变量 g_val 但是我们发现了一个奇怪的现象&#xff1a;在子进程中改变 g_val &#xff0c;由于进程的独立性&#xff0c;所以子进程和父进程的值不一样是可以理解的&#xff0c;但是为什么变量…

20240718每日后端------------kafka VS RabbitMQ:选择正确的消息代理

目标 消息队列选型 Kafka VS RabbitMQ Kafka Apache Kafka 是一个开源分布式事件流平台&#xff0c;以其高吞吐量、容错性和实时数据处理能力而闻名。 Kafka 遵循发布-订阅模型&#xff0c;生产者将消息写入主题&#xff0c;消费者订阅这些主题以接收消息。 Kafka 将消息存储…

【C++11】线程

本篇文章更多的是熟悉一下C11的线程库接口&#xff0c;与linux的相关线程接口是非常相似的&#xff0c;更多的是将面向过程改为了面向对象。 并没有一些概念的讲解。 想知道线程的相关概念的可以看一看这篇文章及后续 在C11之前&#xff0c;涉及到多线程问题&#xff0c;都是和…

访问控制系列

目录 一、基本概念 1.客体与主体 2.引用监控器与引用验证机制 3.安全策略与安全模型 4.安全内核 5.可信计算基 二、访问矩阵 三、访问控制策略 1.主体属性 2.客体属性 3.授权者组成 4.访问控制粒度 5.主体、客体状态 6.历史记录和上下文环境 7.数据内容 8.决策…

使用TableConvert API将CSV转换为JSON数组

TableConvert API 是一款多功能工具&#xff0c;旨在简化不同数据格式之间的转换过程。通过访问370种不同的转换器&#xff0c;该API可以在包括CSV、Excel、HTML、JSON、Markdown等多种文件类型和结构之间实现无缝数据转换。 为什么选择TableConvert的CSV到JSON数组API&#x…

面试问题:react的Reconciler(调度器)为什么在做异步可中断不用原生Generator,自己做了一个Fiber

首先Generator也是有异步中断功能的但是能他是有传染性的&#xff0c;使用了Generator则需要上下文的其他函数也需要做主改变&#xff0c;这样心智负担比较重&#xff0c;就比如说我定义一个Generator方法&#xff0c;里面有ABC三个函数我分别在B的前面和C的前面放一个yield打断…

Linux: network: device事件注册机制 chatGPT; notify

ChatGPT 在 Linux 内核中,有关网络设备(net-device)的事件注册机制,允许用户在网络设备的状态发生变化(例如设备被删除、添加或修改)时接收通知。这主要通过 netdev 事件通知机制实现。具体来说,内核提供了一组用于注册和处理网络设备事件的 API。 以下是一些关键组件…

memcached 高性能内存对象缓存

memcached 高性能内存对象缓存 memcache是一款开源的高性能分布式内存对象缓存系统&#xff0c;常用于做大型动态web服务器的中间件缓存。 mamcached做web服务的中间缓存示意图 当web服务器接收到请求需要处理动态页面元素时&#xff0c;通常要去数据库调用数据&#xff0c;但…

【快速逆向一/无过程/有源码】《大学》在线投稿系统

逆向日期&#xff1a;2024.07.18 使用工具&#xff1a;Node.js 加密工具&#xff1a;Crypto-js标准库 文章全程已做去敏处理&#xff01;&#xff01;&#xff01; 【需要做的可联系我】 【点赞 收藏 关注 】仅供学习&#xff0c;仅供学习&#xff0c; 本文为快速逆向&#x…

如果制作红星照耀中国思维导图?6个软件帮助你快速制作思维导图

如果制作红星照耀中国思维导图&#xff1f;6个软件帮助你快速制作思维导图 制作《红星照耀中国》思维导图可以帮助更好地理解和梳理书中的重要信息和内容。以下是六款推荐的思维导图软件及其特点和使用方法&#xff0c;帮助你快速制作高质量的思维导图。 迅捷画图 特点与功…

Milvus核心组件(2)---- etcd 详解

目录 背景 etcd 简介 1. 基本概念 2. 数据存储特性 3. KVS的操作 4. 租约(Lease)机制 5. 实际应用场景 Milvus 下的 etcd 服务及存储结构 etcd 服务 端口 存储位置 安全连接信息 嵌入式方式运行 etcd 文件存储结构 解析etcd 文件 连接 etcd server 注意事项…

n2. Web相关知识和工具

Web相关知识和工具 1. http协议相关基础知识2. http协议状态码3. Web相关工具2.1 links2.2 wget2.3 curl2.4 httpie 4. httpd的压力测试工具 1. http协议相关基础知识 URI&#xff1a; Uniform Resource Identifier 统一资源标识&#xff0c;分为URL 和 URN URN&#xff1a;U…

Python基础语法篇(下)+ 数据可视化

Python基础语法&#xff08;下&#xff09; 数据可视化 一、函数&#xff08;一&#xff09;函数的定义&#xff08;二&#xff09;函数的调用和传参 二、文件操作&#xff08;一&#xff09;文件读取和写入&#xff08;二&#xff09;文件对象及方法&#xff08;三&#xff09…