leetcode刷题day13|二叉树Part01(递归遍历、迭代遍历、统一迭代、层序遍历)

server/2024/11/14 15:38:39/

递归遍历

思路:使用递归的方式比较简单。
1、递归函数的传参:因为最后输出一个数组,所以需要传入根节点和一个容器,本来想写数组,但发现长度不能确定,所以选择list。
2、终止条件:当访问的节点为空时,return
3、递归函数的逻辑:先访问一个节点,递归访问其他节点

144.二叉树的前序遍历

代码如下:

class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result=new ArrayList<>();preorder(root,result);return result;}public void preorder(TreeNode root,List<Integer> result){if(root==null) return;result.add(root.val);preorder(root.left,result);preorder(root.right,result);}
}

145.二叉树的后序遍历

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

94.二叉树的中序遍历

class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> result=new ArrayList<>();inOrder(root,result);return result;}public void inOrder(TreeNode root,List result){if(root==null) return;inOrder(root.left,result);result.add(root.val);inOrder(root.right,result);}
}

迭代遍历

先序遍历

思路:由于先序遍历是中左右,现将根节点入栈。设置循环判断栈是否为空。弹出根节点并记录val,依次判断右节点和左节点是否为空,不为空则入栈。这样第二次循环就会先弹出左节点,对左节点进行记录和进一步判断。
即先序遍历顺序:中-左-右;入栈顺序中-右-左
代码如下:

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

中序遍历

思路:由于中序遍历是左中右,所以需要不断的查找左节点。先建立一个指针指向根节点,判断指针或栈不为空时进入循环,当当前指针不为空时,将指针节点入栈,并使指针指向该节点的左节点,当当前节点为空但栈不为空时,弹出栈头节点并记录val,将右节点入栈。重复循环。
代码如下:

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

后序遍历

思路:先序遍历得到的结果是中左右,只需修改先序遍历代码得到中右左,再将结果反转即为后序遍历想要的结果。

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

如果直接进行后序遍历,会比较麻烦。
第一步需要先见一个指针和循环将左节点全部入栈,之后弹出栈顶元素,判断栈顶元素的右孩子是否为空或者之前已经访问过(这里需要建立一个指针pre记录之前处理过的右孩子),如果成立则记录该节点,并将该节点记为pre,令node为null;否则需要将该节点重新放回栈中,并将指针指向他的右孩子。
代码如下:

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

统一迭代

思路:采用标记法对在将节点入栈时对需要处理的节点进行标记,即在处理的节点放入栈之后,紧接着放入一个空指针作为标记。
每种遍历都在中间节点的后面放入null,但是由于遍历顺序不同,所以存入中间节点的顺序也不同。先序遍历希望得到的结果是中左右,所以入栈顺序是右左中null;中序遍历希望得到的结果是左中右,所以入栈顺序是右中null左;后序遍历希望得到的结果是左右中,所以入栈顺序是中null右左。
代码如下

先序遍历

class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result=new ArrayList<>();if(root==null) return result;Stack<TreeNode> stack=new Stack<>();stack.push(root);while(!stack.isEmpty()){TreeNode node=stack.pop();if(node!=null){//先放右节点if(node.right!=null) stack.push(node.right);if(node.left!=null) stack.push(node.left);//最后放中间节点stack.push(node);//存入nullstack.push(null);}else{node=stack.pop();result.add(node.val);}}return result;}
}

中序遍历

class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> result=new ArrayList<>();if(root==null) return result;Stack<TreeNode> stack=new Stack<>();stack.push(root);while(!stack.isEmpty()){TreeNode node=stack.pop();if(node!=null){//先放右节点if(node.right!=null) stack.push(node.right);//再放中间节点stack.push(node);//存入nullstack.push(null);//最后放左节点if(node.left!=null) stack.push(node.left);}else{node=stack.pop();result.add(node.val);}}return result;}
}

后序遍历

class Solution {public List<Integer> postorderTraversal(TreeNode root) {List<Integer> result=new ArrayList<>();if(root==null) return result;Stack<TreeNode> stack=new Stack<>();stack.push(root);while(!stack.isEmpty()){TreeNode node=stack.pop();if(node!=null){//先放中间节点stack.push(node);//存入nullstack.push(null);//再放右节点if(node.right!=null) stack.push(node.right);//最后放左节点if(node.left!=null) stack.push(node.left);}else{node=stack.pop();result.add(node.val);}}return result;}
}

层序遍历

思路:借助队列先进先出,一层层遍历。可以通过队列的长度来判断某一层是否遍历完成,每次pull长度减一。掌握队列方法,代码实现就比较简单了

102.二叉树的层序遍历

代码如下:

class Solution {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> result=new ArrayList<>();if(root==null) return result;Queue<TreeNode> queue=new LinkedList<>();queue.offer(root);while(!queue.isEmpty()){int len=queue.size();List<Integer> levelResult=new ArrayList<>();while(len>0){TreeNode node=queue.poll();levelResult.add(node.val);if(node.left!=null) queue.offer(node.left);if(node.right!=null) queue.offer(node.right);len--;}result.add(levelResult);}return result;}
}

递归方法思路:1、终止条件:节点为null时返回;2、传入的参数:一个记录深度的变量deep,每次调用递归函数时传入节点、deep和result;3、递归函数逻辑:每次调用deep深度加一,当result列表中的元素值小于deep时新建一个每层的list列表添加到result列表。获取result列表中下标为当前层数-1的list列表加入当前节点的val。分别对该节点的左右孩子调用递归函数。
代码如下:

 */
class Solution {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> result=new ArrayList<>();lOrder(root,0,result);return result;}public void lOrder(TreeNode root,int deep,List<List<Integer>> result){if(root==null) return;deep++;while(result.size()<deep){List<Integer> levelResult=new ArrayList<>();result.add(levelResult);}result.get(deep-1).add(root.val);lOrder(root.left,deep,result);lOrder(root.right,deep,result);}
}

层序遍历还有一些题,可能会在之后另出帖子一起写。。。


http://www.ppmy.cn/server/119634.html

相关文章

Windows上,使用远程桌面连接Ubuntu

要在 Ubuntu 上设置公网 IP 并通过 Windows 远程桌面连接到 Ubuntu&#xff0c;你需要完成以下步骤&#xff1a; 设置 Ubuntu 公网 IP&#xff1a; 确保你的 Ubuntu 服务器已经配置了一个公网 IP 地址。 你可以通过云服务提供商&#xff08;如 AWS、Azure、Google Cloud&#…

uView使用心得

说实话我不爱用这个库&#xff0c;感觉很鸡肋&#xff0c;坑很多&#xff0c;可能没用习惯 picker选择器 绑定默认值是通过设置index&#xff0c;并且这个index需要通过api设置进去&#xff0c;设置defalutindex绑定值无效&#xff08;只有初始化可以&#xff0c;后面动态改变…

《Python数据分析基础》第一章-Python基础(1.4-1.4.4)

1.4 Python语言基础要素 1.4.1 数值 1.4.1.1 整数 x 9 print("Output #4: {0}".format(x)) print("Output #5: {0}".format(3**4)) #3的4次方# 浮点型转为整型会进行向下取整 print("Output #6: {0}".format(int(8.3)/int(2.7)))方法int(x […

linux-Linux 内核与模块管理-内核基础

Linux 内核是操作系统的核心&#xff0c;它负责管理硬件资源和提供系统调用接口供用户程序使用。Linux 内核的设计极为灵活和模块化&#xff0c;它允许开发者通过加载和卸载模块来动态地扩展内核的功能。 一、Linux 内核概述 1.1 内核的基本功能 Linux 内核的主要功能可以分…

Vue3使用Websocket进行跨页面通信

安装 npm i ws 安装vue3响应式库 npm i vue/reactivity 服务端创建连接--nodejs // Nodejs 端 index.js// 引入 WebSocket 库 const WebSocket require(ws); // 引入 Vue 响应式 API const reactivity require(vue/reactivity)const {ref,computed,watch } reactivity/…

相亲交友程序系统开发产品分析

相亲交友系统是一种专门为单身人士设计的社交平台&#xff0c;旨在帮助他们找到合适的伴侣。这类系统通常包括了线上和线下的多种互动方式&#xff0c;能够让参与者在舒适的环境中相识、相知。编辑&#xff1a;qawsed2466。以下是相亲交友系统的一些关键特点和优势&#xff1a;…

Eclipse 数据空间组件(EDC)项目介绍

探索数据共享新时代——Eclipse 数据空间组件&#xff08;EDC&#xff09;项目介绍 在当今数字经济的背景下&#xff0c;数据成为了新的“石油”。但与石油不同的是&#xff0c;数据可以无限共享且再生。然而&#xff0c;如何在保持数据主权的前提下实现高效、安全的数据共享&…

HarmonyOS ArkTS 用户首选项的开发及测试

本节以一个“账本”为例&#xff0c;使用首选项的相关接口实现了对账单的增、删、改、查操作&#xff0c;并使用自动化测试框架arkxtest来对应用进行自动化测试。 为了演示该功能&#xff0c;创建一个名为“ArkTSPreferences”的应用。应用源码可以在文末《跟老卫学HarmonyOS开…