庖丁解牛-二叉树的遍历

庖丁解牛-二叉树的遍历

在这里插入图片描述

〇、前言

01 文章内容

  • 一般提到二叉树的遍历,我们是在说
    • 前序遍历、中序遍历、后序遍历和层序遍历
  • 或者说三序遍历+层序遍历,毕竟三序和层序的遍历逻辑相差比较大
  • 下面讨论三序遍历的递归方法、非递归方法和非递归迭代的统一方法
  • 然后再讨论一下层序的一般迭代方法(通过队列)

02 力扣网址

  • 144. 二叉树的前序遍历 - 力扣(LeetCode)
  • 94. 二叉树的中序遍历 - 力扣(LeetCode)
  • 145. 二叉树的后序遍历 - 力扣(LeetCode)

一、前序遍历

01 递归实现

  • 递归的基本逻辑是比较简单的,但是注意根据题目的需求不同,实现方式是存在差异的
  • 如果题目要求主函数返回一个结果列表,那么就要构造一个辅助函数来帮助实现
  • 如果题目只要求函数打印前序遍历的序列,那么一个函数就足够了
(1) 返回列表版本1

返回列表版本:辅助函数携带结果列表

public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();inorderTraversalHelper(root,result);return result;}
void preorderTraversalHelper(TreeNode root,List<Integer> result){if(root == null) return;result.add(root.val);inorderTraversalHelper(root.left,result);inorderTraversalHelper(root.right,result);return;
}
(2) 返回列表版本2

返回列表版本:设置全局变量

List<Integer> result = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {inorderTraversalHelper(root,result);return result;
}
void preorderTraversalHelper(TreeNode root){if(root == null) return;result.add(root.val);inorderTraversalHelper(root.left,result);inorderTraversalHelper(root.right,result);return;
}
(3) 纯真打印版本
public List<Integer> preorderTraversal(TreeNode root) {inorderTraversalHelper(root,result);return result;
}
void preorderTraversal(TreeNode root){if(root == null) return;System.out.print(root.val);inorderTraversalHelper(root.left,result);inorderTraversalHelper(root.right,result);return;
}
(4) 面向对象版本
class Solution {class TraverBox{List<Integer> list;TraverBox(){list = new ArrayList<>();}void preorderTraversalHelper(TreeNode root) {list.add(root.val);}void preTraverHelper(TreeNode root) {if(root == null) return;list.add(root.val);preTraverHelper(root.left);preTraverHelper(root.right);}List<Integer> preTraver(TreeNode root) {preTraverHelper(root);return list;}}public List<Integer> preorderTraversal(TreeNode root) {TraverBox tox = new TraverBox();tox.preTraver(root);return tox.list;}
}

02 非递归实现

(1) 一般迭代法

(2) 统一迭代法
public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result = new LinkedList<>();Stack<TreeNode> stack = new Stack<>();TreeNode subRoot = new TreeNode();if (root != null) stack.push(root); //将根结点入栈while(!stack.isEmpty()){subRoot = stack.pop(); //弹出获取栈顶结点if(subRoot != null){//===右===if(subRoot.right != null){// 添加右结点(空结点不入栈)stack.push(subRoot.right);}//===左===if(subRoot.left != null){// 添加左节点(空结点不入栈)stack.push(subRoot.left);}//===中===stack.push(subRoot); // 添加中结点stack.push(null); // 中结点访问过,但是还没有处理,加入空结点做为标记。}else{ // 只有遇到空结点的时候,才将下一个结点放进结果集result.add(stack.pop().val); //重新取出栈中元素,加入到结果集}}return result;
}

二、中序遍历

01 递归实现

(1) 返回列表版本1

返回列表版本:辅助函数携带结果列表

public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();inorderTraversalHelper(root,result);return result;}
void preorderTraversalHelper(TreeNode root,List<Integer> result){if(root == null) return;inorderTraversalHelper(root.left,result);result.add(root.val);inorderTraversalHelper(root.right,result);return;
}
(2) 返回列表版本2

返回列表版本:设置全局变量

List<Integer> result = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {inorderTraversalHelper(root,result);return result;
}
void preorderTraversalHelper(TreeNode root){if(root == null) return;inorderTraversalHelper(root.left,result);result.add(root.val);inorderTraversalHelper(root.right,result);return;
}
(3) 纯真打印版本
void preorderTraversal(TreeNode root){if(root == null) return;inorderTraversalHelper(root.left,result);System.out.print(root.val);inorderTraversalHelper(root.right,result);return;
}

02 非递归实现

(1) 一般迭代法
void inOrderNonRecur(){Stack<TreeNode> stack = new Stack<>();TreeNode subRoot = root;if (subRoot != null) {while (!stack.isEmpty() || subRoot != null) {if (subRoot != null) {stack.push(subRoot);subRoot = subRoot.left;} else {subRoot = stack.pop();System.out.print("【"+subRoot.val+"】");subRoot = subRoot.right;}}}
}
(2) 统一迭代法

带注释版本

public List<Integer> inorderTraversal(TreeNode root) {List<Integer> result = new LinkedList<>();Stack<TreeNode> stack = new Stack<>();TreeNode subRoot = new TreeNode();if (root != null) stack.push(root);while (!stack.isEmpty()) {subRoot = stack.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中if (subRoot != null) {//===右===if(subRoot.right != null){// 添加右节点(空节点不入栈)stack.push(subRoot.right);}//===中===stack.push(subRoot); // 添加中节点stack.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。//===左===if(subRoot.left != null){// 添加左节点(空节点不入栈)stack.push(subRoot.left);}} else { // 只有遇到空节点的时候,才将下一个节点放进结果集result.add(stack.pop().val); // 加入到结果集}}return result;
}

无注释版本

public List<Integer> inorderTraversal(TreeNode root) {List<Integer> result = new LinkedList<>();Stack<TreeNode> stack = new Stack<>();TreeNode subRoot = new TreeNode();if (root != null) stack.push(root);while (!stack.isEmpty()) {subRoot = stack.pop();if (subRoot != null) {if(subRoot.right != null) stack.push(subRoot.right);stack.push(subRoot);stack.push(null);if(subRoot.left != null) stack.push(subRoot.left);} else {result.add(stack.pop().val);}}return result;
}

三、后序遍历

01 递归实现

(1) 返回列表版本1

返回列表版本:辅助函数携带结果列表

public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();inorderTraversalHelper(root,result);return result;}
void preorderTraversalHelper(TreeNode root,List<Integer> result){if(root == null) return;inorderTraversalHelper(root.left,result);inorderTraversalHelper(root.right,result);result.add(root.val);return;
}
(2) 返回列表版本2

返回列表版本:设置全局变量

List<Integer> result = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {inorderTraversalHelper(root,result);return result;
}
void preorderTraversalHelper(TreeNode root){if(root == null) return;inorderTraversalHelper(root.left,result);inorderTraversalHelper(root.right,result);result.add(root.val);return;
}
(3) 纯真打印版本
void preorderTraversal(TreeNode root){if(root == null) return;inorderTraversalHelper(root.left,result);inorderTraversalHelper(root.right,result);System.out.print(root.val);return;
}

02 非递归实现

(1) 一般迭代法
public List<Integer> postorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();if (root != null) {Stack<TreeNode> stack = new Stack<TreeNode>();stack.push(root);TreeNode subRoot = null;while (!stack.isEmpty()) {subRoot = stack.peek();if (subRoot.left != null && root != subRoot.left && root != subRoot.right) {stack.push(subRoot.left);} else if (subRoot.right != null && root != subRoot.right) {stack.push(subRoot.right);} else {result.add(stack.pop().val);root = subRoot;}}}return result;
}
(2) 双栈迭代法
public List<Integer> postOrderNonRecurByTwoStack(){List<Integer> result = new ArrayList<>();TreeNode subRoot = root;if (subRoot != null) {Stack<TreeNode> s1 = new Stack<TreeNode>();Stack<TreeNode> s2 = new Stack<TreeNode>();s1.push(subRoot);while (!s1.isEmpty()) {subRoot = s1.pop();s2.push(subRoot);if (subRoot.left != null) {s1.push(subRoot.left);}if (subRoot.right != null) {s1.push(subRoot.right);}}while (!s2.isEmpty()) {result.add(s2.pop().val);}}
}
(3) 统一迭代法
public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result = new LinkedList<>();Stack<TreeNode> stack = new Stack<>();TreeNode subRoot = new TreeNode();if (root != null) stack.push(root); //将根结点入栈while(!stack.isEmpty()){subRoot = stack.pop(); //弹出获取栈顶结点if(subRoot != null){//===中===stack.push(subRoot); // 添加中结点stack.push(null); // 中结点访问过,但是还没有处理,加入空结点做为标记。//===右===if(subRoot.right != null){// 添加右结点(空结点不入栈)stack.push(subRoot.right);}//===左===if(subRoot.left != null){// 添加左节点(空结点不入栈)stack.push(subRoot.left);}}else{ // 只有遇到空结点的时候,才将下一个结点放进结果集result.add(stack.pop().val); //重新取出栈中元素,加入到结果集}}return result;
}

四、层序遍历

01 不分层输出

class Solution {public int[] levelOrder(TreeNode root) {//if(root == null) return new int[]{};ArrayList<Integer> result = new ArrayList<Integer>();Queue<TreeNode> queue = new LinkedList<TreeNode>();TreeNode subRoot = new TreeNode();if(root != null) queue.offer(root);while(!queue.isEmpty()){subRoot = queue.poll();result.add(subRoot.val);if(subRoot.left != null) queue.add(subRoot.left);if(subRoot.right != null) queue.add(subRoot.right);}int[] dest = new int[result.size()];for(int i = 0 ; i < result.size() ; i++){dest[i] = result.get(i);}return dest;}
}

02 分层输出

public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> ret = new ArrayList<List<Integer>>();if (root == null) {return ret;}Queue<TreeNode> queue = new LinkedList<TreeNode>();queue.offer(root);while (!queue.isEmpty()) {List<Integer> level = new ArrayList<Integer>();int currentLevelSize = queue.size();for (int i = 1; i <= currentLevelSize; ++i) {TreeNode node = queue.poll();level.add(node.val);if (node.left != null) {queue.offer(node.left);}if (node.right != null) {queue.offer(node.right);}}ret.add(level);}return ret;
}

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

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

相关文章

Python编程语言的特点和优点

Python编程语言的特点和优缺点 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程 &#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; …

设计模式复习

设计模式 1、什么是设计模式 一个模式描述了一个在我们周围不断重复发生的问题以及该问题的解决方案的核心。这样&#xff0c;你就能一次又一次地使用该方案而不必做重复劳动.尽管Alexander所指的是城市和建筑模式&#xff0c;但他的思想也同样适用于于面向对象设计模式&…

【DDD】学习笔记-发布者—订阅者模式

在领域设计模型中引入了领域事件&#xff0c;并不意味着就采用了领域事件建模范式&#xff0c;此时的领域事件仅仅作为一种架构或设计模式而已&#xff0c;属于领域设计模型的设计要素。在领域设计建模阶段&#xff0c;如何选择和设计领域事件&#xff0c;存在不同的模式&#…

Jenkins 中部署Nodejs插件并使用,并构建前端项目(3)

遇到多个版本nodeJS需要构建的时候 1、第一种就是一个配置安装&#xff0c;然后进行选中配置 2、第二种就是插件&#xff1a;nvm-wrapper&#xff0c;我们还是选用NodeJS插件&#xff1a; &#xff08;1&#xff09;可以加载任意npmrc文件&#xff1b; &#xff08;2&#x…

【Unity自制手册】Unity—Camera相机跟随的方法大全

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

Python自动化UI测试之Selenium基础实操

1. Selenium简介 Selenium 是一个用于 Web 应用程序测试的工具。最初是为网站自动化测试而开发的&#xff0c;可以直接运行在浏览器上&#xff0c;支持的浏览器包括 IE&#xff08;7, 8, 9, 10, 11&#xff09;&#xff0c;Mozilla Firefox&#xff0c;Safari&#xff0c;Googl…

MariaDB落幕和思考

听过MySQL的基本也都知道 MariaDB。MariaDB由MySQL的创始人主导开发&#xff0c;他早前曾以10亿美元的价格&#xff0c;将自己创建的公司MySQL AB卖给了SUN&#xff0c;此后&#xff0c;随着SUN被甲骨文收购&#xff0c;MySQL的所有权也落入Oracle的手中。传闻MySQL的创始人担心…

Windows环境下查看磁盘层级占用空间的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

信号信号槽

三、信号槽 概念 信号和槽是两种函数&#xff0c;这是Qt在C基础上新增的特性&#xff0c;类似于其他技术中的回调的概念。 信号槽通过程序员提前设定的“约定”&#xff0c;可以实现对象之间的通信&#xff0c;有两个先决条件。 通信的对象都是在QOBject类中派生出来的。 QOBje…

【数据结构】顺序表实现的层层分析!!

关注小庄 顿顿解馋◍˃ ᗜ ˂◍ 引言&#xff1a;本篇博客我们来认识数据结构其中之一的顺序表&#xff0c;我们将认识到什么是顺序表以及顺序表的实现&#xff0c;请放心食用~ 文章目录 一.什么是顺序表&#x1f3e0; 线性表&#x1f3e0; 顺序表 二.顺序表的实现&#x1f3e0…

2024年1月京东洗衣机行业数据分析:TOP10品牌销量销额排行榜

鲸参谋监测的京东平台1月份洗衣机市场销售数据已出炉&#xff01; 根据鲸参谋电商数据分析平台显示&#xff0c;今年1月份&#xff0c;京东平台上洗衣机的销量约160万件&#xff0c;环比上个月增长约42%&#xff0c;同比去年下滑7%&#xff1b;销售额约28亿元&#xff0c;环比…

四、矩阵的分类

目录 1、相等矩阵 2、同形矩阵 3、方阵&#xff1a; 4、负矩阵、上三角矩阵、下三角矩阵&#xff1a; 5、对角矩阵&#xff1a;是方阵 ​编辑7、单位矩阵&#xff1a;常常用 E或I 来表示。它是一个方阵 8、零矩阵&#xff1a; 9、对称矩阵&#xff1a;方阵 1、相等矩阵 …