二叉树的存储方式和遍历方式

文章目录

  • 二叉树的存储方式
  • 二叉树的遍历方式
    • DFS--递归遍历
    • DFS--迭代遍历
    • BFS--层次遍历 LC102

二叉树的存储方式

链式存储(指针)或 顺序存储(数组)

(1)链式存储:通过指针把分布在各个地址的节点串联一起。

(2)顺序存储:元素在内存是连续分布的,就是用数组来存储二叉树。
遍历方式:如果父节点的数组下标是 i,那么它的左孩子就是 2i + 1,右孩子 2i + 2,孩子的父节点为(i-1)/2。

链式存储的二叉树节点的定义方式(二叉树的定义和链表是差不多的,相对于链表 ,二叉树的节点里多了一个指针, 有两个指针,指向左右孩子)

public class TreeNode {
    int val;
    TreeNode left; //表示左子节点的引用,类型为TreeNode
    TreeNode right;
    
    TreeNode() {}
    TreeNode(int val) {
        this.val = val;
    }
    TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

二叉树的遍历方式

  • 广度优先遍历

    • 层次遍历(迭代法)
  • 深度优先遍历

    • 前序遍历(递归法,迭代法)
    • 中序遍历(递归法,迭代法)
    • 后序遍历(递归法,迭代法)

DFS–递归遍历

// 前序遍历·递归·LC144_二叉树的前序遍历
class Solution {
  public List<Integer> preorderTraversal(TreeNode root) {
      List<Integer> result = new ArrayList<Integer>();
      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);
  }

  public void preorder(TreeNode root, List<Integer> result) {
  //     if (root != null) {
  //     result.add(root.val);
  //     preorder(root.left, result);
  //     preorder(root.right, result);
  //     }
  // }

}
// 中序遍历·递归·LC94_二叉树的中序遍历
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        inorder(root, res);
        return res;
    }
    void inorder(TreeNode root, List<Integer> list) {
        if (root == null) {
            return;
        }
        inorder(root.left, list);
        list.add(root.val);             
        inorder(root.right, list);
    }
}
// 后序遍历·递归·LC145_二叉树的后序遍历
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        postorder(root, res);
        return res;
    }
    void postorder(TreeNode root, List<Integer> list) {
        if (root == null) {
            return;
        }
        postorder(root.left, list);
        postorder(root.right, list);
        list.add(root.val);           
    }
}

DFS–迭代遍历

// 前序遍历顺序:中-左-右,入栈顺序:中-右-左
class Solution {
  public List<Integer> preorderTraversal(TreeNode root) {
      List<Integer> result = new ArrayList<>();
      //必须要先判断,因为如果root==null,在执行 stack.push(root)时将会抛出空指针异常
      if (root == null){
          return result;
      }
      Stack<TreeNode> stack = new Stack<>();
      stack.push(root);
      while (!stack.isEmpty()){
          TreeNode node = stack.pop();
          result.add(node.val);
          if (node.right != null){
              stack.push(node.right);
          }
          if (node.left != null){
              stack.push(node.left);
          }
      }
      return result;
  }
}

// 中序遍历顺序: 左-中-右 入栈顺序: 左-右
class Solution {
  public List<Integer> inorderTraversal(TreeNode root) {
      List<Integer> result = new ArrayList<>();
      Stack<TreeNode> stack = new Stack<>();
      TreeNode cur = root;
      //stack.push(root);(不能先把根节点入栈)
      while(cur != null || !stack.isEmpty()){
          // 尽可能深入左子树
          if(cur != null){
              stack.push(cur);
              cur = cur.left;
          }
          //当前节点为空,说明左子树已经遍历完毕,弹出栈顶元素,再处理右子树
          else{
              cur = stack.pop();
              result.add(cur.val);
              cur = cur.right;
          }
      }
      return result;
  }
}

// 后序遍历:先序遍历是中左右,我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转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();
          result.add(node.val);
          if (node.left != null){
              stack.push(node.left);
          }
          if (node.right != null){
              stack.push(node.right);
          }
      }
      Collections.reverse(result);
      return result;
  }
}

BFS–层次遍历 LC102

//BFS--迭代方式--借助队列  (题源)
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> resList = new ArrayList<>();
        if (root == null) {
            return resList;
        }
	    //创建一个队列,使用 LinkedList 作为底层实现
        Queue<TreeNode> que = new LinkedList<>();
        que.offer(root);  //将元素插入到队尾
        while(!que.isEmpty()){
            List<Integer> itemList = new ArrayList<>();
            int levelSize = que.size();
            //for(int i = 0;i < que.size();i++)   不正确,因为for循环过程中size会变化
            for (int i = 0; i < levelSize; i++) {
			    //移除并返回队列头部的元素,如果队列为空,则返回null
                TreeNode tmpNode = que.poll();
                itemList.add(tmpNode.val);
                if(tmpNode.left != null){
                    que.offer(tmpNode.left);
                }
                if(tmpNode.right != null){ 
                    que.offer(tmpNode.right);
                }
            }
            resList.add(itemList);
        }
        return resList;
    }
}

//BFS--递归方式
class Solution {
    List<List<Integer>> resList = new ArrayList<>();
    public List<List<Integer>> levelOrder(TreeNode root) {
        // 初始层级为0,调用递归函数处理
        checkFun01(root, 0);
        return resList;
    }    
    
    public void checkFun01(TreeNode node, int deep) {
        if (node == null) {
            return;
        }
        deep++;
        //当层级增加时,确保resList中已经有足够的层级列表
        if (resList.size() < deep) {
            resList.add(new ArrayList<Integer>());
        }
        // 将当前节点值加入对应层级的列表中
        resList.get(deep - 1).add(node.val);
        // 递归处理左右子节点
        checkFun01(node.left, deep);
        checkFun01(node.right, deep);
    }
}



LC107自底向上的层序遍历,就是在最后将集合翻转即可:Collections.reverse(resList);

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

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

相关文章

docker上传离线镜像包到Artifactory

docker上传离线镜像包到Artifactory 原创 大阳 北京晓数神州科技有限公司 2024年10月25日 17:33 北京 随着docker官方源的封禁&#xff0c;最近国内资源也出现无法拉取的问题&#xff0c;Artifactory在生产环境中&#xff0c;很少挂外网代理去官方源拉取&#xff0c;小编提供…

大模型面试-Layer normalization篇

1. Layer Norm 的计算公式写一下&#xff1f; 2. RMS Norm 的计算公式写一下&#xff1f; 3. RMS Norm 相比于 Layer Norm 有什么特点&#xff1f; 4. Deep Norm 思路&#xff1f; 5. 写一下 Deep Norm 代码实现&#xff1f; 6.Deep Norm 有什么优点&#xff1f; 7.LN 在 LLMs …

每日一题之电话号码的字母组合

给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例 1&#xff1a; 输入&#xff1a;digits "23" 输出&#…

微信小程序学习实录11:精通表单数据绑定,构建高效用户界面

微信小程序中的表单数据绑定是一种非常实用的功能&#xff0c;它允许开发者将页面上的表单元素与数据进行关联&#xff0c;从而实现数据的双向绑定。这样做的好处是能够简化代码&#xff0c;提高开发效率&#xff0c;并且让数据管理变得更加直观。 一、基本概念 数据绑定&am…

Spring Cloud +UniApp智慧工地源码,智慧工地综合解决方案,建筑工程云平台源码

Spring Cloud UniApp智慧工地源码&#xff0c;智慧工地全套源代码包含&#xff1a;PC端大屏端移动端 智慧工地解决方案以工程建设现场管理需求为主线&#xff0c;以AI、物联网、BIM技术为手段&#xff0c;对施工现场进行立体化、全方位、全时段管理&#xff0c;实现规范施工管…

解决VMware虚拟机的字体过小问题

前言&#xff1a; &#xff08;1&#xff09;先装VMware VMware17Pro虚拟机安装教程(超详细)-CSDN博客 &#xff08;2&#xff09;通过清华等镜像网站安装好Ubuntu镜像&#xff0c;下面贴上链接 教程虚拟机配置我没有做&#xff0c;因为学校给了现成的虚拟机~~大家需要的自己…

数据结构之单链表——考研笔记

文章目录 一.单链表定义1.什么是单链表2.代码实现3.不带头结点的单链表4.带头结点的单链表 二.单链表插入删除1.按位序插入&#xff08;带头结点&#xff09;2.插入时不带头节点3.指定节点的后插操作4.指定节点的前插操作5.按位序删除&#xff08;带头结点&#xff09;6.删除指…

2024年【北京市安全员-A证】找解析及北京市安全员-A证考试试卷

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 北京市安全员-A证找解析考前必练&#xff01;安全生产模拟考试一点通每个月更新北京市安全员-A证考试试卷题目及答案&#xff01;多做几遍&#xff0c;其实通过北京市安全员-A证证考试很简单。 1、【多选题】《中华人…

保姆级教程 | 全流程免费:合并多份长宽不同的PDF成相同大小并进行瘦身

背景 由于老板需要&#xff0c;完成不同PDF文件&#xff08;a&#xff0c;b&#xff0c;c....&#xff09;合并&#xff0c;同时要求主文件&#xff08;A&#xff09;小于6M。合并过程中发现各个PDF大小&#xff08;长宽&#xff09;并不相同&#xff0c;造成合并后效果不好也…

网站安全问题都有哪些,分别详细说明

网站安全问题涉及多个方面&#xff0c;以下是一些常见的网站安全问题及其详细说明&#xff1a; 数据泄露 问题描述&#xff1a;数据泄露是指网站存储的用户敏感信息&#xff08;如用户名、密码、信用卡信息等&#xff09;被非法获取。黑客可能通过SQL注入、XSS攻击等手段窃取这…

Unity编辑器界面及其基础功能介绍

文章目录 Unity编辑器界面编辑器默认界面布局打开和关闭编辑界面自定义界面布局Unity资源商店Unity Assets Store什么是资源商店&#xff1f;资源商店中包含哪些东西&#xff1f;如何进行素材导入&#xff1f;Unity官网购买素材或插件导入方法非官网素材导入非官网插件导入 Sce…

【WRF数据准备】基于GEE下载静态地理数据-叶面积指数LAI及绿色植被率Fpar

【WRF数据准备】基于GEE下载静态地理数据 准备:WRF所需静态地理数据(Static geographical data)数据范围说明基于GEE下载叶面积指数及绿色植被率GEE数据集介绍数据下载:LAI(叶面积指数)和Fpar(绿色植被率)数据处理:基于Python处理为单波段LAI数据参考GEE的介绍可参见另…

基于Django+python的酒店客房入侵检测系统设计与实现

项目运行 需要先安装Python的相关依赖&#xff1a;pymysql&#xff0c;Django3.2.8&#xff0c;pillow 使用pip install 安装 第一步&#xff1a;创建数据库 第二步&#xff1a;执行SQL语句&#xff0c;.sql文件&#xff0c;运行该文件中的SQL语句 第三步&#xff1a;修改源…

Spring beanFactoryPostProcessor

项目结构和代码 Component public class CustomerBeanFactoryPostProcessor implements BeanFactoryPostProcessor {Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {System.out.printl…

基于Spring Boot的宿舍管理系统设计与实现(源码+定制+开发)宿舍信息管理平台、智能宿舍系统开发、学生宿舍管理平台设计、宿舍入住与信息管理

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

华为:高级ACL 特定ip访问特定ip命令

网络拓扑图&#xff1a; 网络环境&#xff1a; 全网互通即可 1.创建一个名为test的高级ACL acl name test advance 2.添加规则 ##拒绝所有ip访问 rule 10 deny ip source any destination 192.168.1.10 0.0.0.0 只允许特定ip访问特定ip rule 5 permit ip source 192.168.2.10…

C++与现代开发实践第三节:多线程与并发编程

第四章&#xff1a;C与现代开发实践 第三节&#xff1a;多线程与并发编程 在这一课中&#xff0c;我们将详细探讨多线程与并发编程的各个方面&#xff0c;特别是从线程的创建、管理到高级的优化技术&#xff0c;并且通过复杂的实战案例来展示如何应对并发问题。最后&#xff…

并联 高电压、高电流 放大器实现 2 倍输出电流模块±2A

1.1 并联输出电路设计注意事项 直接对两个功率运算放大器的输出进行硬接线并不是一种好的电气做法。如果两个运算放大器的输出直接连接在一起&#xff0c;则可能会导致不均匀的电流共享。这是因为其中的每个运算放大器都尝试强制施加略微不同的 Vout 电压&#xff0c;该电压取决…

【HarmonyOS NEXT】使用 Navigation 对折叠屏设备页面进行分栏展示,优化 UI 交互

关键词&#xff1a;折叠屏、navigation、router、路由、分栏、UI 随着科技的发展&#xff0c;手机设备形态也由一面屏向多面屏进行发展&#xff0c;那么软件的UI适配也面临着问题&#xff0c;本篇文章主要解决大屏设备的页面 UI 适配问题&#xff0c;如折叠屏&#xff0c;平板&…

Spring Boot 3项目创建与示例(Web+JPA)

以下是一个Spring Boot 3.3.4整合JPA的示例,它展示了如何在Spring Boot应用程序中使用JPA进行数据持久化。 版本与环境 Spring Boot 3.3.4数据库: MySQL 8.0.40, MySQL的安装使用可以参考: MySQL 8 下载与安装攻略JDK 17Maven 3.6项目创建 可以使用Spring Initializr 初始…