算法打卡day12|二叉树篇01|144. 二叉树的前序遍历、94. 二叉树的中序遍历、145. 二叉树的后序遍历

二叉树理论基础篇

二叉树的定义

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

JAVA的定义如下,需要理解性记忆,因为面试手撕代码可能会用。

public class TreeNode {
    int val;//值
    TreeNode left;//左子树
    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;
    }
}

二叉树的种类

满二叉树

定义:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。

如图所示:这棵二叉树为满二叉树,也可以说深度为k,有2^k-1个节点的二叉树。

完全二叉树

定义:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层(h从1开始),则该层包含 1~ 2^(h-1) 个节点。

看一个典型的例子:

二叉搜索树

二叉搜索树是必须有数值的,因为二叉搜索树是一个有序树。遵循下面三条规则

  1. 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  2. 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  3. 它的左、右子树也分别为二叉排序树

下面这两棵树都是二叉搜索树

平衡二叉搜索树

平衡二叉搜索树(AVL):具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树

如图:最后一棵 不是平衡二叉树,因为它的左右两个子树的高度差的绝对值超过了1。

二叉树的存储方式

二叉树可以链式存储,也可以顺序存储。

那么链式存储方式就用指针, 顺序存储的方式就是用数组。顺序存储的元素在内存是连续分布的,而链式存储则是通过指针把分布在各个地址的节点串联一起。

链式存储如图:

顺序存储的方式如图:

用数组来存储二叉树在遍历时,如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1,右孩子就是 i * 2 + 2。但是用链式表示的二叉树,更有利于我们理解,所以一般都是用链式存储二叉树

二叉树的遍历方式

二叉树主要有两种遍历方式:

  1. 深度优先遍历:先往深走,遇到叶子节点再往回走。
  2. 广度优先遍历:一层一层的去遍历。

再从深度优先遍历和广度优先遍历进一步拓展,才有如下遍历方式:

  • 深度优先遍历
    • 前序遍历(递归法,迭代法)
    • 中序遍历(递归法,迭代法)
    • 后序遍历(递归法,迭代法)
  • 广度优先遍历
    • 层次遍历(递归法,迭代法)

其中深度优先遍历,这里前中后,其实指的就是中间节点的遍历顺序

如下图:

深度优先遍历,前中后序遍历的逻辑其实都是可以借助栈使用递归的方式来实现的,因为其实就是递归的一种实现结构,而广度优先遍历的实现一般使用队列来实现,这也是队列先进先出的特点所决定的,因为需要先进先出的结构,才能一层一层的来遍历二叉树。

大佬视频讲解:

关于二叉树,你该了解这些!| 二叉树理论基础一网打尽i

算法题

大佬视频讲解:

二叉树递归前中后序遍历

二叉树的非递归遍历前后序

二叉树的非递归遍历中序

Leetcode  144. 二叉树的前序遍历

题目链接:144. 二叉树的前序遍历

解法
递归法

搞定递归算法的三个要素。

  1. 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。

  2. 确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。

  3. 确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        //1.确定递归函数的参数和返回值  
        List<Integer> res= new ArrayList<Integer>();//结果数组
        preorder(root,res);//递归遍历
        return res;
    }

    public void preorder (TreeNode root, List<Integer> res){
        //2.确定终止条件
        if(root==null) { return ;}

        //3.确定单层递归的逻辑; 前序遍历: 中左右
        res.add(root.val);//中
        preorder(root.left,res);//左;获取左子树值
        preorder(root.right,res);//右;获取右子树值
    }
}

时间复杂度:O(n);(遍历二叉树)

空间复杂度:O(n);(一个列表

非递归法(迭代法)

前序遍历是中左右,每次先处理的是中间节点,那么先将根节点放入栈中,然后将右孩子加入栈,再加入左孩子。先将右孩子入栈,因为这样出栈的时候才是中左右的顺序。

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res= new ArrayList<Integer>();//结果数组
        if(root ==null) return res;

        Stack<TreeNode>  stack=new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node =stack.pop();
            res.add(node.val);

            if(node.right!=null){//先放入右孩子
                stack.push(node.right);
            }
            if(node.left!=null){//再放入左孩子
                stack.push(node.left);
            }
        }
    return res;
    }


}

.

时间复杂度:O(n);(遍历字符数组)

空间复杂度:O(n);(结果列表)

Leetcode 94. 二叉树的中序遍历

题目链接:94. 二叉树的中序遍历

解法
递归法

前序遍历递归法改一下顺序即可

// 中序遍历·递归·LC94_二叉树的中序遍历
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        //1.确定递归函数的参数和返回值  
        List<Integer> res = new ArrayList<>();
        inorder(root, res);
        return res;
    }

    void inorder(TreeNode root, List<Integer> list) {
        //2.确定终止条件
        if (root == null) {
            return;
        }

       //3.确定单层递归的逻辑; 中序遍历: 左中右
        inorder(root.left, list);//左
        list.add(root.val); //中   
        inorder(root.right, list);//右
    }
}

时间复杂度:O(n);(遍历二叉树)

空间复杂度:O(n);(一个列表

非递归法(迭代法)

上面前序遍历迭代法的代码,不能和中序遍历通用;因为前序遍历的顺序是中左右,先访问的元素是中间节点,要处理的元素也是中间节点,要访问的元素和要处理的元素顺序是一致的,都是中间节点。但中序遍历,中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进result数组中),这就造成了处理顺序和访问顺序是不一致的那么在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。

// 中序遍历顺序: 左-中-右 入栈顺序: 左-右
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null){
            return result;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = 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;
    }
}

时间复杂度:O(n);(遍历字符数组)

空间复杂度:O(n);(结果列表)

Leetcode 145. 二叉树的后序遍历

题目链接:145. 二叉树的后序遍历

解法
递归法

前序遍历递归法改一下顺序即可

// 后序遍历·递归·LC145_二叉树的后序遍历
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        //1.确定递归函数的参数和返回值  
        List<Integer> res = new ArrayList<>();
        postorder(root, res);
        return res;
    }

    void postorder(TreeNode root, List<Integer> list) {
        //2.确定终止条件
        if (root == null) {
            return;
        }

       //3.确定单层递归的逻辑; 后序遍历: 左右中

        postorder(root.left, list);//左
        postorder(root.right, list);//右
        list.add(root.val); // 中;添加值
    }
}

时间复杂度:O(n);(遍历二叉树)

空间复杂度:O(n);(一个列表

非递归法(迭代法)

前序遍历迭代法结果翻转一下即可;

// 后序遍历顺序 左-右-中 入栈顺序:中-左-右 出栈顺序:中-右-左, 最后翻转结果
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;
    }
}

时间复杂度:O(n);(遍历字符数组和翻转,2n)

空间复杂度:O(n);(结果列表)

以上是个人的思考反思与总结,若只想根据系列题刷,参考卡哥的网址代码随想录算法官网代码随想录算法官网代码随想录算法官网

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

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

相关文章

VBA中类的解读及应用第十讲:限制文本框的输入,使其只能输入数值(上)

《VBA中类的解读及应用》教程【10165646】是我推出的第五套教程&#xff0c;目前已经是第一版修订了。这套教程定位于最高级&#xff0c;是学完初级&#xff0c;中级后的教程。 类&#xff0c;是非常抽象的&#xff0c;更具研究的价值。随着我们学习、应用VBA的深入&#xff0…

10大AI工具

ChatGPT ChatGPT是由OpenAI开发的人工智能聊天机器人程序&#xff0c;全称为Chat Generative Pre-trained Transformer。它基于GPT-3.5架构&#xff0c;能够生成回答并根据聊天上下文进行互动。ChatGPT具备强大的对话能力&#xff0c;能在同一会话中回答上下文相关的问题&…

SpringCloud之Nacos入门与实战系列

目录 一、Nacos介绍 1.1、配置中心和注册中心的概念 1.2 Nacos 优点 二、Nacos的使用 2.1 以单机模式启动Nacos 2.2 Nacos部署方式介绍 2.3 配置数据源 2.4 开启控制台权限登录 三、配置中心的使用 3.1 创建配置信息 3.2 SpringBoot使用配置中心 四、注册中心的使用 4…

知识管理系统:初创企业的智慧助手

一、什么是知识管理系统 用通俗易懂的语言来解释&#xff0c;知识管理系统就像一个超级大脑&#xff0c;帮助企业和团队更好地记住、分享和使用他们学到的东西。无论是工作中的经验、方案还是项目成果&#xff0c;这个系统都能帮大家保存下来&#xff0c;并方便以后查找和使用。…

程序如何知道mqtt设备是否在线

在做物联网设备的时候经常会碰到设备的在线与掉线 问题&#xff1a;emqx如何来实现这个在线与掉线 实现&#xff1a;添加一个规则&#xff0c;程序监控这个规则 1、SELECT * FROM "$events/client_connected", "$events/client_disconnected" 2、添加一…

全面认识计算机

目录 一、计算机的发展史 1. 电子管计算机时代 2. 晶体管计算机时代 3. 小、中规模集成电路计算机时代 4. 大、超大规模集成电路计算机时代 二、计算机硬件组成 1. 输入设备 2. 输出设备 3. 存储器 4. 运算器 5. 控制器 三、计算机硬件间的连接 四、计算机系统的结…

AlpacaEval Leaderboard大模型排行榜

参考 Model NameWin RateLengthGPT-4 Turbo &#x1f4c4;50.00%2049Contextual AI (KTO-Mistral-PairRM) &#x1f4c4;33.23%2521Yi 34B Chat &#x1f4c4;29.66%2123Claude 3 Opus (02/29) &#x1f4c4;29.04%1388Claude 3 Sonnet (02/29) &#x1f4c4;25.56%1420GPT-4 …

数睿通2.0数据接入升级——支持增量字段同步,表单独映射

引言 上次数睿通 2.0 更新是在 23 年12 月 底&#xff0c;已经过去了接近三个月的时间&#xff0c;中间由于过年加上年前年后实在是工作繁忙&#xff0c;所以一直没有腾出空来更新代码&#xff0c;希望大家可以理解&#xff0c;平台的发展离不开你们的支持&#xff0c;在此表示…

Seata 2.x 系列【4】产品简介

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Spring Boot 版本 3.1.0 本系列Seata 版本 2.0.0 源码地址&#xff1a;https://gitee.com/pearl-organization/study-seata-demo 文章目录 1. 概述2. 发展历史3. 核心术语3.1 TC3.2 TM3.3 RM 4.…

泽众云真机-选择时长套餐?还是选择不限时套餐?

泽众云真机2月底推出了不限时套餐&#xff0c;改变了传统时长计费套餐&#xff0c;对用户来说&#xff0c;选择困难症状又来了&#xff0c;两种计费模式&#xff0c;我应该如何选择呢&#xff1f; 首先&#xff0c;说说平台为什么上线不限时套餐&#xff0c;之前平台运维和客服…

在vue3中根据element Plus封装一个图片上传组件

继上次文件上传之后&#xff0c;可能又遇到多个图片上传&#xff0c;图片如下 组件使用方法如下 话不多说&#xff0c;直接上组件&#xff0c;上面的划入删除是手写的&#xff0c;组件里面只有多图片上传的&#xff0c;索性就自己写了个划入显示点击删除的 下面是代码 <te…

❤ Vue3项目使用yarn 搭建 Vue3+Pinia+Vant3/ElementPlus+typerscript 系统篇(一)

❤ Vue3 完整项目搭建 Vue3PiniaVant3/ElementPlustyperscript系统篇&#xff08;一&#xff09; 1、项目环境和简介 环境 使用nvm 版本 20.10.0 node 版本 20.10.0 npm版本 10.2.3 项目简介&#xff1a; Vue3全家桶viteTSPiniaVant3/ElementPlus-搭建Vue3.x项目 项目开源地…

Dgraph 入门教程五(Shema)

要想做好图数据库&#xff0c;必须做图数据库设计&#xff0c;想做好Dgraph&#xff0c;就需要设计好Shema。Shema的语法是必须理解&#xff0c;如果不理解&#xff0c;别人写的Shema&#xff0c;我们也看不懂。我这里也是走马观花式的记录&#xff0c;细节还需要在使用的时候去…

AES加密学习

AES&#xff08;高级加密标准&#xff09;是一种对称密钥加密算法&#xff0c;用于加密和解密数据。它被广泛应用于各种安全领域&#xff0c;包括但不限于网络通信、数据存储和软件保护。 历史背景 AES是由比利时密码学家Joan Daemen和Vincent Rijmen设计的Rijndael算法演变而…

家用洗地机哪个型号好用?介绍几个值得考虑的品牌

作为家里的主要清洁工&#xff0c;我一直以来都是负责家里的清洁工作。我经常使用吸尘器和扫地机器人来轮流清洁&#xff0c;虽然效果还不错&#xff0c;但是这种方式太费时间和精力了。特别是在脸上厨房里做完饭和孩子吃完饭后留下的残渣时&#xff0c;我总是需要用传统的拖多…

超级简单的Docker安装(centos7)

文章目录 先安装所需要的工具包设置远程仓库安装启动docker查看版本 先安装所需要的工具包 yum install -y yum-utils #安装工具包&#xff0c;缺少这些依赖将无法完成&#xff1b;设置远程仓库 yum-config-manager --add-repo https://download.docker.com/linux/centos/doc…

【漏洞复现】锐捷 EWEB auth 远程命令执行漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

洗地机热门品牌测评:石头/希亦/顺造/云鲸洗地机哪个好?哪个牌子最值得入手

大家好&#xff0c;博主是一个热爱生活和科技的居家测评博主。在过去的三年多时间里&#xff0c;我专注于清洁家电——洗地机。我深入测评了三十多款洗地机&#xff0c;现在我将用简单易懂的语言来分享洗地机的选购技巧和热门洗地机机型推荐。 洗地机选购技巧&#xff1a; 看…

掌握java中继承

目录 1.概念&#xff1a; 2.使用&#xff1a; 3.super关键字 4.子类构造方法 5.super和this关键字 6.初始化时代码块的执行顺序 7.继承的方式 8.final关键字 1.概念&#xff1a; 是面向对象程序设计代码可以重复使用的重要手段&#xff0c;允许程序员在保持原有类特性的…

#stm32外设总结电容触摸按键

BS8116A-3 IRQ 外部中断请求 NMOS输出内部上拉 SCL SDA IIC通信接口 VDD 供电电压2.2-5.5V Ct电容: 0~25 pF 电容越大灵敏度越低 1、 软件使用流程 初始化 将IIC的两个引脚初始化为复用开漏模式 按键引脚设置上拉输入 下降沿触发外部中断 void KEY_Init(void) {//uint8_t …