当前位置: 首页 > news >正文

【算法系列-二叉树】二叉树遍历系列(递归+迭代)

【算法系列-二叉树】二叉树遍历系列(递归+迭代)

欢迎来到【算法系列】第六弹 🏆 二叉树,接下来我们将围绕二叉树这类型的算法题进行解析与练习!一起加油吧!!( •̀ ω •́ )✧✨

文章目录

  • 【算法系列-二叉树】二叉树遍历系列(递归+迭代)
    • 1. 算法分析🛸
    • 2. 递归遍历
      • 2.1 思路分析🎯
      • 2.2 代码示例🌰
        • 2.2.1 前序遍历
        • 2.2.2 中序遍历
        • 2.2.3 后序遍历
    • 3. 迭代遍历
      • 3.1 思路分析🎯
      • 3.2 代码示例🌰
        • 3.2.1 前序遍历
        • 3.2.2 后序遍历
        • 3.2.3 中序遍历
      • 3.3 统一迭代法🎬

1. 算法分析🛸

在二叉树中,前中后序遍历其实就是中间节点的遍历顺序

  • 前序遍历:中左右
  • 中序遍历:左中右
  • 后序遍历:左右中

如图所示:

在这里插入图片描述

前序遍历结果:1 2 3 4 5 6

中序遍历结果:3 2 1 5 4 6

后序遍历结果:3 2 5 6 4 1

对此,有两种方式来对二叉树进行遍历,即 递归迭代

2. 递归遍历

2.1 思路分析🎯

通过递归的方式来对二叉树进行遍历,而使用递归需要明确三个部分:

  1. 递归参数
  2. 终止条件
  3. 执行内容

在这里,我们递归参数需要一个遍历节点和一个存放返回数据的数组,而终止条件就是当遍历到的节点为空时则返回,执行内容即按当前遍历方式取中节点的值存入返回数组,并按顺序遍历其它分支节点

2.2 代码示例🌰

2.2.1 前序遍历

【题目链接】144. 二叉树的前序遍历 - 力扣(LeetCode)

class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> ret = new ArrayList<>();preorder(root, ret);return ret;}public void preorder(TreeNode cur, List<Integer> list) {if (cur == null) {return;}list.add(cur.val);preorder(cur.left, list);preorder(cur.right, list);}
}
2.2.2 中序遍历

【题目链接】94. 二叉树的中序遍历 - 力扣(LeetCode)

class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> ret = new ArrayList<>();inorder(root, ret);return ret;}void inorder(TreeNode cur, List<Integer> list) {if (cur == null) {return;}inorder(cur.left, list);list.add(cur.val);inorder(cur.right, list);}
}
2.2.3 后序遍历

【题目链接】145. 二叉树的后序遍历 - 力扣(LeetCode)

class Solution {public List<Integer> postorderTraversal(TreeNode root) {List<Integer> ret = new ArrayList<>();postorder(root, ret);return ret;}void postorder(TreeNode cur, List<Integer> list) {if (cur == null) {return;}postorder(cur.left, list);postorder(cur.right, list);list.add(cur.val);}
}

3. 迭代遍历

3.1 思路分析🎯

迭代遍历的方式是通过来操作我们的二叉树节点(递归的底层实现便是用到了调用栈)

在不同的顺序中,节点进入栈的顺序也是不同的**(因为栈是先进后出的**):

  • 前序遍历:因为要实现中左右,则 遇到中节点则将中节点的值加入结果集,之后右节点先入栈,紧接着左节点再入栈;
  • 后序遍历:因为要实现左右中,相当于 中右左翻转,则 中节点顺序同上,之后左节点先入栈,紧接着右节点再入栈,最后反转数组;

3.2 代码示例🌰

3.2.1 前序遍历

【题目链接】144. 二叉树的前序遍历 - 力扣(LeetCode)

class Solution {public List<Integer> preorderTraversal(TreeNode root) {if (root == null) {return new ArrayList<>();}Stack<TreeNode> stack = new Stack<>();List<Integer> ret = new ArrayList<>();TreeNode cur = root;stack.push(cur);while (!stack.isEmpty()) {cur = stack.pop();if (cur != null) {ret.add(cur.val);stack.push(cur.right);stack.push(cur.left);}}return ret;}
}
3.2.2 后序遍历

【题目链接】145. 二叉树的后序遍历 - 力扣(LeetCode)

前中后序的实现只需要交换一下左右节点入栈顺序即可,记得反转数组

class Solution {public List<Integer> postorderTraversal(TreeNode root) {if (root == null) {return new ArrayList<>();}Stack<TreeNode> stack = new Stack<>();List<Integer> ret = new ArrayList<>();TreeNode cur = root;stack.push(cur);while (!stack.isEmpty()) {cur = stack.pop();if (cur != null) {ret.add(cur.val);stack.push(cur.left);stack.push(cur.right);}}Collections.reverse(ret);return ret;}
}
3.2.3 中序遍历

【题目链接】94. 二叉树的中序遍历 - 力扣(LeetCode)

中序遍历有些不同,无法按上述的顺序进行排列,开始它需要先一直遍历左节点直到左节点为空时再进行中节点结果存储,并开始遍历右节点

class Solution {public List<Integer> inorderTraversal(TreeNode root) {if (root == null) {return new ArrayList<>();}Stack<TreeNode> stack = new Stack<>();List<Integer> ret = new ArrayList<>();TreeNode cur = root;while (cur != null || !stack.isEmpty()) {if (cur != null) {stack.push(cur);cur = cur.left;}else {cur = stack.pop();ret.add(cur.val);cur = cur.right;}}return ret;}
}

3.3 统一迭代法🎬

上述迭代方式中,中序遍历与前后续遍历的迭代方式存在着一些不同,但想让迭代遍历能和递归遍历一样有一个大概统一的模板,对此提供下述的方法:

// 中序遍历
class Solution {public List<Integer> inorderTraversal(TreeNode root) {if (root == null) {return new ArrayList<>();}Stack<TreeNode> stack = new Stack<>();List<Integer> ret = new ArrayList<>();TreeNode cur = root;stack.push(cur);while (!stack.isEmpty()) {cur = stack.peek();if (cur != null) {stack.pop(); // 避免重复使用节点if (cur.right != null) {stack.push(cur.right);}stack.push(cur);stack.push(null); // 加入空节点表示当前中间节点并未处理if (cur.left != null) {stack.push(cur.left);}}else {stack.pop(); // 弹出空节点cur = stack.pop();ret.add(cur.val);}}return ret;}
}

只有在当前节点为空的时候才处理节点的数据,不同的序列只需要交换中间节点的入栈顺序即可

// 前序遍历
if (cur.right != null) {stack.push(cur.right);
}
if (cur.left != null) {stack.push(cur.left);
}
stack.push(cur);
stack.push(null); // 加入空节点表示当前中间节点并未处理
../ // 后序遍历
stack.push(cur);
stack.push(null); // 加入空节点表示当前中间节点并未处理
if (cur.right != null) {stack.push(cur.right);
}
if (cur.left != null) {stack.push(cur.left);
}
../

以上便是对二叉树遍历系列问题的介绍了!!后续还会继续分享其它算法系列内容,如果这些内容对大家有帮助的话请给一个三连关注吧💕( •̀ ω •́ )✧( •̀ ω •́ )✧✨


http://www.mrgr.cn/news/58251.html

相关文章:

  • 飞驰云联与中科红旗签订战略合作协议并完成产品兼容性互认证
  • 每日一练 | MPLS 标签字段的长度
  • XShell 中实现免密登录 Linux 服务器的详细流程
  • 软件部署-Docker容器化技术(二)
  • html 登入界面,用户注册界面相关的标签及案例
  • 业内1688运营都在用的店雷达竞品分析法!收藏了偷偷学…
  • 钰泰ETA4553电压电平转换器IC
  • 网络安全行业10大副业汇总,总有一个适合你
  • libevent源码剖析-evconnlistener
  • 不是网吧去不起,而是云电脑更具性价比
  • 筋膜枪哪个品牌最好性价比最高?倍益康M2 Pro Max,航天科技助力全家按摩体验
  • STM32--I2C通信
  • 轻松拿下offer,一次真实的面试回答记录
  • 最强开源大模型面世:阿里发布Qwen2
  • LINUX设备可以上网,但是外部设备连接linux设备之后,外部设备无法上网
  • 新版本发布丨向企业级实时计算平台迈进!支持存算分离、FICC 函数库大更新!
  • DDD系列 - 番外篇1 记一些常用的架构设计原则
  • ReentrantReadWriteLock底层实现原理?
  • vue3中ref和reactive的用法,区别和优缺点,以及使用场景
  • FMEA 系统在医疗设备行业的重要性与创新_SunFMEA
  • 漏洞挖掘 | 记一次逻辑漏洞修改任意用户密码
  • 【主机漏洞扫描常见修复方案】:Tomcat安全(机房对外Web服务扫描)
  • CSS简介
  • 气膜建筑:突破传统建筑的优势—轻空间
  • 大学新生如何开启高效学习编程之路
  • 书客、孩视宝、霍尼韦尔护眼大路灯哪款更好?对比测评谁是top1!