迭代实现二叉树的遍历-算法通关村

news/2024/4/29 23:26:29

迭代实现二叉树的遍历-算法通关村


  • 理论上,递归能做的迭代一定能做,但可能会比较复杂。有时候面试官要求不使用递归实现三种遍历,递归就是每次执行方法调用都会先把当前的局部变量、参数值和返回地址等压入栈中,后面在递归返回的时候,从栈顶弹出上一层的各项参数继续执行,这就是递归为什么可以自动返回并执行上一层方法的原因。

1 迭代法实现前序遍历

  • 前序遍历是中左右,如果还有左子树就一直向下找。完了之后再返回从最底层逐步向上向右找。
    不难写出如下代码:(注意代码中,空节点不入栈)

  •   public List<Integer> preOrderTraversal(TreeNode root){List<Integer> res = new ArrayList<>();//存放遍历的结果if(root == null){return res;}Deque<TreeNode> stack = new LinkedList<>();TreeNode node = root;while(!stack.isEmpty() || node != null){while(node != null){//空节点不入栈res.add(node.val);stack.push(node);node = node.left;}//当当前节点的所有左子节点都已遍历后,// 将栈顶元素出栈,并将node更新为该节点的右子节点。// 然后继续执行内部循环,遍历右子树。node = stack.pop();node = node.right;}return res;}
    

2 迭代法实现中序遍历

  • 中序遍历是左中右,先访问的是二叉树左子树的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进res列表中)。在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。看代码:

  •   public List<Integer> inOrderTraversal(TreeNode root){List<Integer> res = new ArrayList<>();Deque<TreeNode> stack = new LinkedList<>();while(!stack.isEmpty() || root != null){while(root != null){//将当前节点入栈,并将root更新为其左子节点。// 这个循环会一直执行,直到当前节点为空,// 即遍历完当前节点的所有左子节点。stack.push(root);root = root.left;}root = stack.pop();res.add(root.val);//将root更新为该节点的右子节点,以便后续遍历右子树root = root.right;}return res;}
    

3 迭代法实现后序遍历

  • 后序遍历的非递归实现有三种基本的思路:反转法、访问标记法、和Morris法,可惜三种理解起来都有些难度,如果头发不够,可以等一等再学习。
    个人感觉访问标记法是最难理解的方法,而Morris法是一个老外发明的巧妙思想:不使用栈,而是用好树中的nul指针,但是实现后序仍然非常麻烦,我们这里不再展开,感兴趣的同学可以查一
    下。

  • 这里只介绍一种好理解又好实现的方法:反转法

  • 如下图,我们先观察后序遍历的结果是 seq = { 9 5 7 4 3 },如果我们将其整体反转的话就是
    new_seq = {3 4 7 5 9}.

  • 有没有发现要得到new_seq的方法和前序遍历思路几乎一致,只不过是左右反了。前序是先中间,再左边然后右边,而这里是先中间,再后边然后左边。那我们完全可以改造一下前序遍历,得到序列new_seq之后再reverse一下就是想要的结果了,代码如下:

  •   public List<Integer> postOrderTraversal(TreeNode root){List<Integer> res = new ArrayList<>();if(root == null){return res;}Deque<TreeNode> stack = new LinkedList<>();TreeNode node = root;while(!stack.isEmpty() || node != null){//将当前节点的值添加到结果列表res中,// 然后将当前节点入栈,并将node更新为其右子节点。// 这个循环会一直执行,直到当前节点为空while(node != null){res.add(node.val);stack.push(node);node = node.right;}node = stack.pop();//将node更新为该节点的左子节点,以便后续遍历左子树。node = node.left;}//列表中的顺序是左子树-右子树-根节点。// 但是后序遍历的正确顺序应该是左子树-右子树-根节点,// 所以需要将结果列表res反转。Collections.reverse(res);return res;}
    

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

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

相关文章

C# NumericUpDown 控件正整数输入控制

用到了控件的 KeyPress 和 KeyUp事件。 KeyPress 中控制输入“点、空格&#xff0c;负号”&#xff1b; KeyUp 中防止删空&#xff0c;以及防止输入超过最大值或最小值 。 private void nudStart_KeyPress(object sender, KeyPressEventArgs e){numericUpDownKeyPress(sender…

SpringBoot整合腾讯云邮件发送服务非STMP

SpringBoot整合腾讯云邮箱服务 1、pom配置 <!-- 腾讯云邮箱服务--><dependency><groupId>com.tencentcloudapi</groupId><artifactId>tencentcloud-sdk-java</artifactId><!-- go to https://search.maven.org/search?qtencen…

硬件15、PCB如何将元器件切换顶层和底层以及元器件布局对齐

器件切换顶层和底层 在移动元器件的时候&#xff0c;按一下 L 键&#xff0c;原器件就会变为蓝色&#xff0c;这就是放到了底层&#xff0c;然后再按 L 键就可以切换到顶层了 元器件放置后布局如何变得对齐那种 首先选中需要对齐的元器件&#xff0c;然后进行设置布局的属性…

vue3+threejs新手从零开发卡牌游戏(二十):添加卡牌被破坏进入墓地逻辑

在game目录下新建graveyard文件夹存放墓地相关代码&#xff1a; game/graveyard/p1.vue&#xff0c;这里主要设置了墓地group的位置&#xff1a; <template><div></div> </template><script setup lang"ts"> import { reactive, ref,…

Git常用指令使用

摘要&#xff1a;之前代码管理都是借助于fork、sourceTree等图形工具&#xff0c;最近发现直接用命令也好用&#xff0c;就总结Git常用的指令 1、Git的介绍 1.1 git官网 安装: Git - Downloading Packagehttps://git-scm.com/download/mac Mac上安装&#xff0c;直接使…

启扬RK3568核心板助力智慧步道轻装健身,打造全民健康生活新方式

随着物联网、AI智能等新技术的快速发展&#xff0c;智慧步道成为全国各地公园建设和全民健身公共服务设施改造的新主题。智慧步道基于物联网、人脸识别、大数据分析等技术&#xff0c;对人们的运动进行监测和数据采集&#xff0c;显示运动数据&#xff0c;包括里程统计、热量消…