【数据结构】二叉树全攻略,从实现到应用详解

news2024/12/25 10:35:41

 💎所属专栏:数据结构与算法学习 

💎 欢迎大家互三:2的n次方_

在这里插入图片描述

 🍁1. 树形结构的介绍

 树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。

以下是树的一些基本术语

节点的度:一个节点含有子树的个数

树的度:一棵树中所有节点度的最大值

叶子节点(终端节点):度为0的节点

双亲节点(父节点):一个节点的直接前驱节点

孩子节点(子节点):一个节点(除了根节点)的直接后继节点

根节点:没有双亲节点的节点

🍁2. 二叉树的介绍

二叉树是每个节点最多有两个子树的树结构,通常称为左子树和右子树,正如名字一样,每一个节点最多有两个子树。

🍁2.1 二叉树的类别

二叉树是树形结构中最重要的一种类型,它有多种特殊形态,如:

  • 完全二叉树:除了最后一层外,每一层都被完全填满,并且所有节点都尽可能地向左对齐。
  • 满二叉树:除了叶子节点外,每个节点都有两个子节点。
  • 平衡二叉树(如AVL树、红黑树):任何节点的两个子树的高度最大差别为一。
  • 搜索二叉树(BST):左子树上所有节点的值均小于它的根节点的值,右子树上所有节点的值均大于它的根节点的值。

🍁2.2 二叉树的基本性质 

对于任意一棵二叉树,深度为 k 的二叉树,最多有 2的k次方 - 1 个节点。

在任何一棵二叉树中,如果度为2的节点数为 n₂,叶节点数为 n₀,则有关系式 n₀=n₂+1。

任意一棵包含 n 个节点的二叉树的高度至少为 log₂⁡(n+1)(即完全二叉树的高度),最多为 n(即所有节点构成一个链表)。 

在具有2 n 个节点的完全二叉树中,叶子节点的个数为 n,2n - 1个节点的完全二叉树中,叶子节点的个数为 n

🍁 2.3 二叉树的存储

二叉树可以通过链式存储和顺序存储的方式存储,这一节主要介绍链式存储

链式存储方式使用节点(Node)对象来表示二叉树的结构。每个节点包含数据部分和两个指针,分别指向其左子节点和右子节点。

例如使用孩子兄弟表示法存储树的效果如下图所示:

 🍁3. 二叉树的实现

class TreeNode {
    int val;
    TreeNode left;//左孩子
    TreeNode right;//右孩子

    TreeNode(int x) {
        val = x;
    }
}

🍁3.1 二叉树的遍历

树的遍历是树的基本操作之一,常见的遍历方式有:

  • 前序遍历:先访问根节点,然后遍历左子树,最后遍历右子树。
  • 中序遍历:在二叉搜索树中,先遍历左子树,然后访问根节点,最后遍历右子树。
  • 后序遍历:先遍历左子树,然后遍历右子树,最后访问根节点。
  • 层序遍历:按从上到下、从左到右的顺序访问树中的每个节点

 🍁3.1.1 先序,中序,后序遍历

    //先序遍历,根左右
    public void preOrder(TreeNode root){
        if(root == null) return;
        System.out.print(root.val + " ");
        preOrder(root.left);
        preOrder(root.right);
    }
    //中序遍历,左根右
    public void inOrder(TreeNode root){
        if(root == null) return;
        inOrder(root.left);
        System.out.print(root.val + " ");
        inOrder(root.right);
    }
    //后序遍历,左右根
    public void postOrder(TreeNode root){
        if(root == null) return;
        postOrder(root.left);
        postOrder(root.right);
        System.out.print(root.val + " ");
    }

🍁3.1.2 层序遍历 

层序遍历的实现需要借助队列来实现,由于队列先进先出的特性,可以依次把头结点,左孩子和右孩子依次入队,接着出队打印,就可以实现层序遍历的效果

    public void levelOrder(TreeNode root) {
        if (root == null) return;
        Queue<TreeNode> q = new LinkedList<>();
        TreeNode cur = root;
        q.offer(root);
        while (!q.isEmpty()) {
            cur = q.poll();
            System.out.print(cur.val + " ");
            if (cur.left != null) q.offer(cur.left);
            if (cur.right != null) q.offer(cur.right);
        }
    }

102. 二叉树的层序遍历

可以试一下这道力扣上的题

 这道题对返回值有了要求,其它的还是正常的层序遍历,答案的形式就是每一层作为一个数组,最终的答案以一个二维顺序表的形式返回

只需要每次入队时计算一下当前队列的元素,把当前层的元素都出队,每次入队的元素也都是下一层的元素 

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if (root == null) return res;
        Queue<TreeNode> q = new LinkedList<>();
        TreeNode cur = root;
        q.offer(root);
        while (!q.isEmpty()) {
            List<Integer> list = new ArrayList<>();
            int size = q.size();
            //当这一层的元素都出队后,下一层的元素也都能入队
            while (size!=0) {
                cur = q.poll();
                list.add(cur.val);
                if (cur.left != null) q.offer(cur.left);
                if (cur.right != null) q.offer(cur.right);
                size--;
            }
            //添加每层的答案
            res.add(list);
        }
        return res;
    }
}

🍁3.2 size()

 求节点数

这里给出遍历和子问题两种思想进行实现

通过前序遍历的方法,通过计数的方式得到二叉树的节点数,分解子问题就是一棵二叉树的每个分支又可以看作一棵二叉树,整个二叉树的节点数就是左子树加上右子树再加上根节点数,根结点数就是1

    public static int sizeNode = 0;
    //遍历思想
    public int size(TreeNode root) {
        if (root == null) return 0;
        sizeNode++;
        size(root.left);
        size(root.right);
        return sizeNode;
    }
    //子问题思想
    public int size2(TreeNode root) {
        if (root == null) return 0;
        return size2(root.left) + size2(root.right) + 1;
    }

🍁3.3 getLeafNodeCount(TreeNode root)

求叶子节点数

依然可以使用两种方法,通过遍历找出叶子节点,分解子问题就是左子树的叶子节点加上右子树的叶子节点等于二叉树的叶子节点,因为根节点肯定不是叶子节点

    public static int leafSize = 0;
    public int getLeafNodeCount(TreeNode root) {
        if (root == null) return 0;
        //判断叶子节点
        if (root.left == null && root.right == null) {
            leafSize++;
        }
        getLeafNodeCount(root.left);
        getLeafNodeCount(root.right);
        return leafSize;
    }

    public int getLeafNodeCount2(TreeNode root) {
        if (root == null) return 0;
        if (root.left == null && root.right == null) return 1;
        return getLeafNodeCount2(root.left) + getLeafNodeCount2(root.right);
    }

🍁3.4 getKLeveLNodeCount(TreeNode root, int k)

获取第 k 层的节点数

    public int getKLeveLNodeCount(TreeNode root, int k) {
        if (root == null) {
            return 0;
        }
        if (k == 1) return 1;
        return getKLeveLNodeCount(root.left, k - 1) + getKLeveLNodeCount(root.right, k -                 1);
    }

🍁3.5 getHeight(TreeNode root)

获取二叉树的高度

还是通过递归来实现,二叉树的高度其实也就是左子树和右子树的最大值,再加上根节点的一层,就是整棵树的高度

    public int getHeight(TreeNode root) {
        if (root == null) return 0;
        return Math.max(getHeight(root.left),getHeight(root.right)) + 1;
    }

🍁3.6 findVal(TreeNode root,char val)

检测val是否存在二叉树中

只需要依次判断根节点,左子树,右子树,通过分解子问题,左子树又可以分为根节点,左子树右子树,依次达到遍历整棵树的效果,判断val是否存在

    public TreeNode findVal(TreeNode root,char val){
        if(root == null) return null;
        if(root.val == val) return root;
        TreeNode t1 = findVal(root.left,val);
        if(t1 != null) return t1;
        TreeNode t2 = findVal(root.right,val);
        if(t2!= null) return t2;
        return null;
    }

🍁3.7 isCompleteTree(TreeNode root)

判断是否为完全二叉树

当遍历二叉树时,如果遍历到的cur节点此时为null,并且此时队列中剩余元素也都是null,那么就是完全二叉树

 反之,如果剩余元素有不为null的,那么就不是完全二叉树,例如下面的图中,当遍历到B的左孩子为null时,此时队列中还有E,G等不为null的元素

    public boolean isCompleteTree(TreeNode root) {
        if (root == null) return false;
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        //找到cur为空时的位置
        while (!q.isEmpty()) {
            TreeNode cur = q.poll();
            if (cur != null) {
                q.offer(cur.left);
                q.offer(cur.right);
            }else {
                break;
            }
        }
        //继续判断剩余队列是否有不为null的元素
        while(!q.isEmpty()){
            if(q.peek()!=null) return false;
            q.poll();
        }
        return true;
    }

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JVM垃圾回收-----垃圾分类

一、垃圾分类定义 垃圾分类是JVM垃圾分类中的第一步&#xff0c;这一步将堆中的对象分为存活对象和垃圾对象两类。 在垃圾分类阶段&#xff0c;JVM会从一组根对象开始&#xff0c;通过对象之间的引用关系&#xff0c;遍历所有的对象&#xff0c;并将所有存活的对象进行标记。…

QT使用QPainter绘制多边形维度图

多边形统计维度图是一种用于展示多个维度的数据的图表。它通过将各个维度表示为图表中的多边形的边&#xff0c;根据数据的大小和比例来确定各个维度的长度。 一、简述 本示例实现六边形战力统计维度图&#xff0c;一种将六个维度的战力统计以六边形图形展示的方法。六个维度是…

leetcode-383.赎金信

题源 383.赎金信 题目描述 给你两个字符串&#xff1a;ransomNote 和 magazine &#xff0c;判断 ransomNote 能不能由 magazine 里面的字符构成。如果可以&#xff0c;返回 true &#xff1b;否则返回 false 。magazine 中的每个字符只能在 ransomNote 中使用一次。示例 1&…

MySQL(3)表的操作

目录 1. 表的操作; 2. 数据类型; 1. 表的操作: 1.1 创建表: 语法: create table 表名( 属性 类型 [comment ], 属性 类型 [comment ], 属性 类型 ) character set 字符集 collate 校验集 engine 存储引擎; 前面博客提到: MyISAM和InoDB这两个比较重要. 1.2 查看表…

Spring与设计模式实战之策略模式

Spring与设计模式实战之策略模式 引言 在现代软件开发中&#xff0c;设计模式是解决常见设计问题的有效工具。它们提供了经过验证的解决方案&#xff0c;帮助开发人员构建灵活、可扩展和可维护的系统。本文将探讨策略模式在Spring框架中的应用&#xff0c;并通过实际例子展示…

three.js领衔,10大基于webGL的JavaScript库。

Three.js的赫赫威名补多少&#xff0c;不了解的自行搜索或者翻看大宇之前的文章&#xff0c;除了three.js外&#xff0c;我想实现web3D效果还有其他库吗&#xff1f;答案是有的&#xff0c;而且还不少。 除了 Three.js&#xff0c;还有一些基于 WebGL 的库和框架&#xff0c;它…

动态环境下的激光slam论文列表

文章目录 Scan Context: Egocentric Spatial Descriptor for Place Recognition within 3D Point Cloud Map&#xff08;2018&#xff09;LIO-CSI: LiDAR inertial odometry with loop closure combined with semantic information&#xff08;2021&#xff09;Semantic Lidar-…

防火墙--双机热备

目录 双击热备作用 防火墙和路由器备份不同之处 如何连线 双机 热备 冷备 VRRP VGMP&#xff08;华为私有协议&#xff09; 场景解释 VGMP作用过程 主备的形成场景 接口故障的切换场景 整机故障 原主设备故障恢复的场景 如果没有开启抢占 如果开启了抢占 负载分…

网络原理(上)

前言&#x1f440;~ 上一章我们介绍了网络的一些基础知识&#xff0c;今天来讲解一下网络原理相关的知识点&#xff0c;分三篇进行阐述内容有点多​​​​​​​ 再谈协议分层 应用层 传输层&#xff08;重点&#xff09; UDP协议 TCP协议 TCP如何完成可靠传输&#xff…

在 PostgreSQL 里如何处理数据的归档和清理过程中的数据完整性验证?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 在 PostgreSQL 里如何处理数据的归档和清理过程中的数据完整性验证 在 PostgreSQL 里如何处理数据的归…

3D数字孪生项目运行卡顿,来看看它要求的电脑配置。

有些小伙伴和我说&#xff0c;数字孪生项目运行卡顿&#xff0c;不知道啥原因&#xff0c;根源还是这类项目是浏览器渲染&#xff0c;对电脑配置要求很高。 运行3D数字孪生项目需要一台性能强大的电脑&#xff0c; 以下是一个推荐的配置清单&#xff1a; 1. 处理器&#xff1…

css实现每个小盒子占32%,超出就换行

代码 <div class"visitors"><visitor class"item" v-for"(user,index) in userArr" :key"user.id" :user"user" :index"index"></visitor></div><style lang"scss" scoped&…

Porfinet转DeviceNet主总线协议转换网关

产品功能 1. 远创智控YC-DNTM-PN型网关是Porfinet从转Devicenet主工业级Porfinet网关。‌这种网关设备允许将Porfinet网络中的设备连接到Devicenet网络中&#xff0c;‌从而实现不同工业通信协议之间的互操作性。‌这些网关设备通常具有两个以太网接口&#xff0c;‌分别用于连…

shell脚本-linux如何在脚本中远程到一台linux机器并执行命令

需求&#xff1a;我们需要从11.0.1.17远程到11.0.1.16上执行命令 实现&#xff1a; 1.让11.0.1.17 可以免密登录到11.0.1.16 [rootlocalhost ~]# ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Created d…

Ubuntu 22.04.4 LTS (linux) 安装iftop 监控网卡流量 软件

1 安装iftop sudo apt update sudo apt-get install iftop 2 监控网卡 sudo iftop -i eth0 -n -p 界面最上面&#xff0c;显示的是类似刻度尺的刻度范围&#xff0c;显示流量图形的长条作标尺用的。 中间的< >这两个左右箭头&#xff0c;表示的是流量的进出方向.TX&…

使用JS和CSS制作的小案例(day二)

一、写在开头 本项目是从github上摘取&#xff0c;自己练习使用后分享&#xff0c;方便登录github的小伙伴可以看本篇文章 50项目50天​编辑https://github.com/bradtraversy/50projects50dayshttps://github.com/bradtraversy/50projects50days有兴趣的小伙伴可以自己去gith…

美式键盘 QWERTY 布局的起源

注&#xff1a;机翻&#xff0c;未校对。 The QWERTY Keyboard Is Tech’s Biggest Unsolved Mystery QWERTY 键盘是科技界最大的未解之谜 It’s on your computer keyboard and your smartphone screen: QWERTY, the first six letters of the top row of the standard keybo…

Redis的热key解决

1、Redis热Key会带来哪些问题 1、流量集中&#xff0c;达到物理网卡上限。 当某一热点 Key 的请求在某一主机上超过该主机网卡上限时&#xff0c;由于流量的过度集中&#xff0c;会导致服务器中其它服务无法进行。 2、请求过多&#xff0c;缓存分片服务被打垮。 如果热点过于…

Linux入门笔记(指令)

操作系统是什么&#xff1f; 操作系统是一款做软硬件管理的软件。计算机系统自下而上可以大致分为4部分&#xff1a;硬件、操作系统、应用程序和用户。操作系统管理各种计算机硬件&#xff0c;为应用程序提供基础&#xff0c;并且充当计算机硬件与用户之间的中介。重点&#x…

泛微e-cology WorkflowServiceXml SQL注入漏洞(POC)

漏洞描述&#xff1a; 泛微 e-cology 是泛微公司开发的协同管理应用平台。泛微 e-cology v10.64.1的/services/接口默认对内网暴露&#xff0c;用于服务调用&#xff0c;未经身份认证的攻击者可向 /services/WorkflowServiceXml 接口发送恶意的SOAP请求进行SQL注入&#xff0c;…