二叉树的遍历(非递归版)

news/2024/12/22 19:54:36/

文章目录

  • 二叉树的前序遍历
  • 二叉树的中序遍历
  • 二叉树的后序遍历

正文开始前给大家推荐个网站,前些天发现了一个巨牛的 人工智能学习网站, 通俗易懂,风趣幽默,忍不住分享一下给大家。 点击跳转到网站。

二叉树的前序遍历

在这里插入图片描述
用递归实现前序遍历非常简单,但是用非递归怎么实现呢?
在这里插入图片描述
比如说这样一棵树,前序遍历是先访问根,再访问左子树、右子树。
但是我们要实现非递归,所以我们肯定要记录每个节点,只有当这个节点,不然我们没办法回来访问右子树,所以我们可以用一个栈,然后一直找到最左边的节点,在把路上节点都push进栈。然后在访问右子树节点。

在这里插入图片描述
我们可以把前序遍历分为这样几个部分,我们每次取一个栈里面的元素,就代表我们已经访问过它的根和左子树了,只需要访问它的右子树就可以了,所以我们去到这个节点后直接pop掉就可以了。只不过我们在找最左边的节点的时候先把这个接点给访问了就可以了。

class Solution {
public:vector<int> preorderTraversal(TreeNode* root) {stack<TreeNode*> st;vector<int> v;//root为空并且栈为空就结束while(root||st.size()){while(root){v.push_back(root->val);st.push(root);root = root->left;}root = st.top()->right;st.pop();}return v;}
};

二叉树的中序遍历

在这里插入图片描述
在这里插入图片描述
同样,我们还是给这样一颗树,中序遍历是要遍历左子树、根、右子树,以这样的次序来遍历。我们可以使用前序遍历的思路,只不过我们先不访问根,我们先找到最左边的节点,然后在访问右子树之前把根给访问了就可以了。

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;}cur = st.top();st.pop();v.push_back(cur->val);cur = cur->right;}return v;}
};

二叉树的后序遍历

在这里插入图片描述
在这里插入图片描述
还是这样一棵树,后序遍历是以左子树、右子树、根,这样的次序来进行遍历。我们会发现,后序遍历用前面两个的思路好像并不能够完成,因为我们访问了右子树会发现根没法访问了,而且我们没法先访问根,我们要先访问它的左子树和右子树然后才能访问根,这样前面的思路就用不了了。

但是我们可以用一个指针来记录上一个访问的节点,但是我们怎么知道这个节点的右子树访问过没有呢?

我们会发现如果当前节点的右子树==记录的上一个节点的指针时,就说明这个颗树的左右子树被访问完了,可以访问根了,或者它的右子树为空也说明可以访问根了,只不过我们在访问的时候,要更新一下prev指针,如果不是这两种情况就说明右子树存在,我们需要访问右子树,直接让当前节点指向它的右孩子就可以了。

ps:每次更新完成后要把cur置空,防止死循环。

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

那么今天的分享就到这里了,有什么不懂得可以私信博主,或者添加博主的微信,欢迎交流。


http://www.ppmy.cn/news/1226567.html

相关文章

Day34力扣打卡

打卡记录 合并石头的最低成本&#xff08;区间DP&#xff09; 链接 与多边形的三角形问题相同&#xff0c;将大问题化小问题&#xff0c;再用中间节点不断地寻找最值。 class Solution:def mergeStones(self, stones: List[int], k: int) -> int:n len(stones)if (n - 1…

【实用技巧】更改ArduinoIDE默认库文件位置,解放C盘,将Arduino15中的库文件移动到其他磁盘

本文主要介绍更改Arduino IDE &#xff08;含2.0以上版本&#xff09;默认库文件位置的方法。 原创文章&#xff0c;转载请注明出处&#xff1a; 【实用技巧】解放系统盘&#xff0c;更改ArduinoIDE默认库文件位置&#xff0c;将Arduino15中的库文件移动到其他磁盘-CSDN博客文…

Python 利用PIL由多张图片合成gif动画

Python 由多张图片合成gif动画 案例 import os figure_save_path "file_fig_test" import warnings warnings.filterwarnings("error") import numpy as np np.random.seed(0) import matplotlib.pyplot as plt from PIL import Image import timenum 1…

curl网络请求命令

curl简介 1、什么是curl2、curl命令的基本使用 1、什么是curl CURL&#xff08;CommandLine Uniform Resource Locator&#xff09;是一个利用URL语法&#xff0c;在命令行终端下使用的网络请求工具&#xff0c;支持HTTP、HTTPS、FTP等协议 Linux、MAC系统一般默认已安装好CUR…

Linux通过端口号找到对应的服务及其安装位置

Linux服务器中&#xff0c;通过端口号找到对应的服务及其安装位置&#xff0c;需要两步操作&#xff0c;如下&#xff1a; 第一步&#xff1a;根据端口号&#xff0c;确定对应的进程号&#xff08;以redis服务为例&#xff09; netstat -antup|grep 6379第二步&#xff1a;通…

MyBatis #{} 和 ${} 的区别

前言&#xff1a; #{} 和 ${} 的区别是 MyBatis 中一个常见的面试题&#xff0c;#{} 和 ${} 是MyBatis 中获取参数的两种方式&#xff0c;但我们在项目中大多数使用的都是 #{} 来获取参数&#xff0c;那么它们两个有什么区别呢&#xff1f; 区别 一. #{} 采用预编译 SQL&…

MatLab的下载、安装与使用(亲测有效)

1、概述 MatLab是由MathWorks公司开发并发布的&#xff0c;支持线性代数、矩阵运算、绘制函数和数据、信号处理、图像处理以及视频处理等功能。广泛用于算法开发、数据可视化、数据分析以及数值计算等。 Matlab 的主要特性包括&#xff1a; 简单易用的语法&#xff0c;使得程…

Linux 之 journalctl 查看系统与 kernel 日志

目录 1. Linux 之 journalctl 查看系统与 kernel 日志 1. Linux 之 journalctl 查看系统与 kernel 日志 1 概述 日志管理工具 journalctl 是 centos7 上专有的日志管理工具, 该工具是从 message 这个文件里读取信息。Systemd 统一管理所有 Unit 的启动日志。带来的好处就是, …