数据结构 - 二叉树

news2025/2/23 0:55:21

文章目录

目录

文章目录

前言

一 . 树型结构

1.1 树的概念(了解)

1.2 数的常用术语 (掌握)

1.3 树的应用(了解)

1.4 树相较于数组和链表的优势(了解)

二 . 二叉树(重点)

2.1 二叉树的概念

2.2 两种特殊的二叉树

 2.3 二叉树的性质

2.4 二叉树的基本操作

2.4.1 二叉树的前序遍历

2.4.2 二叉树的中序遍历

2.4.3 二叉树的后序遍历

2.4.4 获取树中节点的个数

2.4.5 获取叶子结点的个数

2.4.6 获取第k层节点的个数

2.4.7 获取二叉树的高度

2.4.8 层序遍历

2.4.9 判断一棵树是否是完全二叉树

总结


前言

大家好,这篇博客给大家带来二叉树的概念,特性和基本操作的实现

目标:

1. 掌握树的基本概念

2. 掌握二叉树概念及特性

3. 掌握二叉树的基本操作


一 . 树型结构

1.1 树的概念(了解)

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

1.有一个特殊的结点,称为根结点,根结点没有前驱结点

2.除根结点外,其余结点被分成M(M > 0)个互不相交的集合T1、T2、......、Tm,其中每一个集合Ti (1 <= i <= m) 又是一棵与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继

3.树是递归定义的。

1.2 数的常用术语 (掌握)

结点的度:一个结点含有子树的个数称为该结点的度; 如上图:A的度为6

树的度:一棵树中,所有结点度的最大值称为树的度; 如上图:树的度为6

叶子结点或终端结点:度为0的结点称为叶结点; 如上图:B、C、H、I...等节点为叶结点

双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点; 如上图:A是B的父结点

孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点; 如上图:B是A的孩子结点

根结点:一棵树中,没有双亲结点的结点;如上图:A

结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推

树的高度或深度:树中结点的最大层次; 如上图:树的高度为4

子孙:以某结点为根的子树中任一结点都称为该结点的子孙。如上图:所有结点都是A的子孙

森林:由m(m>=0)棵互不相交的树组成的集合称为森林

1.3 树的应用(了解)

  1. 文件系统:文件系统通常使用树的结构来组织文件和目录,每个目录都可以包含多个子目录和文件。

  2. 数据库索引:数据库中的索引通常使用树的结构来快速定位和访问数据。

  3. 网络路由:网络路由器使用树的结构来决定数据包的传输路径,以实现高效的数据传输。

  4. 组织架构:组织架构通常使用树的结构来表示不同部门、岗位和员工之间的关系。

  5. 表达式求值:编译器和计算器可以使用树的结构来解析和求值数学表达式。

  6. 人工智能:决策树和搜索树是人工智能中常用的算法,用于决策和规划。

  7. 图形学:图形学中的场景图和层次模型使用树的结构来表示和操作图形对象。

  8. 数据压缩:哈夫曼树是一种常用的数据压缩算法,用于将频率较高的字符编码为较短的编码。

  9. 操作系统:操作系统中的进程调度和内存管理等功能通常使用树的结构来组织和管理进程和内存资源。

  10. AI算法:神经网络和决策树等AI算法中使用树的结构来表示和处理数据。

 总而言之,树这种数据结构应用十分广泛,基本上涵盖了生活的方方面面,十分重要!

1.4 树相较于数组和链表的优势(了解)

  1. 快速插入和删除:树的结构允许快速插入和删除节点,时间复杂度为O(log n),而数组的插入和删除操作通常需要移动其他元素,时间复杂度为O(n)。
  2. 快速搜索:树的结构使得搜索操作更加高效,时间复杂度为O(log n),而数组需要遍历所有元素,时间复杂度为O(n)。
  3. 有序性:树的结构可以保持元素的有序性,使得范围查询等操作更加高效。
  4. 灵活性:树的结构可以适应动态变化的数据集,可以很容易地添加、删除和修改节点,而数组的大小通常是固定的。
  5. 适用于层次结构:树的结构可以很好地表示层次结构的数据,比如文件系统、组织架构等。
  6. 适用于排序和搜索算法:树的结构可以很好地支持排序和搜索算法,比如二叉搜索树、平衡二叉树等。

总之,树的结构在插入、删除、搜索等操作上具有较高的效率,并且适用于表示层次结构和支持排序和搜索算法。

二 . 二叉树(重点)

接下来就进入了树的重点内容了,大家打起精神来!

2.1 二叉树的概念

二叉树是一种特殊的树结构,其中每个节点最多有两个子节点,分别称为左子节点和右子节点。二叉树的特点是每个节点最多有两个子节点,且子节点的顺序是固定的,即左子节点在前,右子节点在后。

二叉树可以为空树,即没有任何节点。如果二叉树不为空,则根节点是二叉树的唯一一个没有父节点的节点,如上图。

2.2 两种特殊的二叉树

1. 满二叉树:  一棵二叉树,如果每层的结点数都达到最大值,则这棵二叉树就是满二叉树。也就是说,如果一棵 二叉树的层数为K,且结点总数是2的k次方-1 ,则它就是满二叉树。

2. 完全二叉树: 完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n 个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从0至n-1的结点一一对应时称之为完 比特就业课 全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。

 2.3 二叉树的性质

1. 若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有 (i>0)个结点

2. 若规定只有根结点的二叉树的深度为1,则深度为K的二叉树的最大结点数是 (k>=0)

3. 对任何一棵二叉树, 如果其叶结点个数为 n0, 度为2的非叶结点个数为 n2,则有n0=n2+1

设树的节点数为N 则连接树的边为N-1,设度为0的节点为n0 度为1的节点为n1 度为2的节点为n2

0 x n0+1 x n1+2 x n2 = N-1;

n0+n1+n2 = N;

解之: n0 = n2 + 1

4. 具有n个结点的完全二叉树的深度k为log2(n+1) 上取整

2.4 二叉树的基本操作

为了二叉树中的方法,我们先来准备一个二叉树

BTNode为节点类,使用内部类的方式,私有化成员变量root

调用createBinaryTree方法模拟下图的二叉树

public class BinaryTree {
    public static class BTNode {
        BTNode left;
        BTNode right;
        int value;

        BTNode(int value) {
            this.value = value;
        }
    }

    private BTNode root;

    public void createBinaryTree(){
        BTNode node1 = new BTNode(1);
        BTNode node2 = new BTNode(2);
        BTNode node3 = new BTNode(3);
        BTNode node4 = new BTNode(4);
        BTNode node5 = new BTNode(5);
        BTNode node6 = new BTNode(6);
        root = node1;
        node1.left = node2;
        node2.left = node3;
        node1.right = node4;
        node4.left = node5;
        node5.right = node6;
    }
}

 

2.4.1 二叉树的前序遍历

前序遍历指的是遍历的顺序为 根节点->左子节点->右子节点

我们有两种实现方式,一种是通过递归实现,还有一种是通过非递归的方式来实现

递归方式:

public void preOrder(BTNode root){
    if(root == null){
        return;
    }
    System.out.println(root.value);
    preOrder(root.left);
    preOrder(root.right);
}

 

 

非递归方式:

步骤:

1.打印当前cur节点的val值

2.如果cur节点有右节点,将其压入栈

3.如果cur节点有左节点,将其压入栈

4.循环上述过程,直到栈为空为止

count 解释: 标志位 保证开始栈为空时不能进入循环,同时用来记录循环的次数

public void preOrder2(BTNode root){
    if(root == null){
        return;
    }
    Stack<BTNode> stack = new Stack();
    BTNode cur = null;
    int count = 0; // 标志位 同时记录循环进行的次数


    while (count == 0 || !stack.empty()){
        if(stack.empty()){
            cur = root;
        }else{
           cur = stack.pop();
        }

        System.out.println(cur.value);

        if(cur.right != null){
            stack.push(cur.right);
        }

        if(cur.left != null){
            stack.push(cur.left);
        }
        count++;
    }
}

2.4.2 二叉树的中序遍历

左子节点 -> 根节点 -> 右子节点

递归

    public void infixOrder(BTNode root){
        if(root == null){
            return;
        }
        infixOrder(root.left);
        System.out.println(root);
        infixOrder(root.right);
    }

非递归

public void infixOrder2(BTNode root) {
    if (root == null) {
        return;
    }
    Stack<BTNode> stack = new Stack<>();
    BTNode cur = root;
    while (true) {
        //循环遍历向左找,直到为空
        while (cur != null) {
            stack.push(cur);
            cur = cur.left;
        }
        //2.如果为空,遍历结束
        if (stack.isEmpty()) {
            break;
        }
        //3.取栈顶元素并访问
        BTNode pop = stack.pop();
        System.out.println(pop.value);
        //4.从当前节点右子树出发
        cur = pop.right;
    }
}

2.4.3 二叉树的后序遍历

左子节点 -> 右子节点-> 根节点

递归

public void postOrder1(BTNode root){
    if(root == null){
        return;
    }
    postOrder1(root.left);
    postOrder1(root.right);
    System.out.println(root.value);
}

 可以看到,前中后序遍历都是相对于根节点来说的

2.4.4 获取树中节点的个数

/**
 * 获取树中节点的个数
 * @param root 根节点
 * @return 返回树中节点的个数
 */
public int getSize(BTNode root){
    if(root == null){
        return 0;
    }
    return getSize(root.left)+getSize(root.right)+1;
}

 这个题还有两种方式,一种是进行前中后序遍历,可解 另一种就是非递归方式,和上面的非递归本质上并无差别

2.4.5 获取叶子结点的个数

/**
 * 获取节点中叶子结点的个数
 * @param root 根节点
 * @return 返回叶子结点的个数
 */
public int getLeafSize(BTNode root){
    if(root == null){
        return 0;
    }
    if(root.left == null && root .right == null){
        return 1;
    }
    return getLeafSize(root.left)+getLeafSize(root.right);
}

 依旧是采用分治的实现,递归实现,把一个问题转化为与之相对应的小问题来解决

这里没有画图的必要,和上面的完全类似,上面能理解,这个就没问题

2.4.6 获取第k层节点的个数

/**
 * 获取的k层节点的个数 规定 root所处的层级为 1
 * @param root 根节点
 * @param k 层数
 * @return 返回值
 */
public int getKSize(BTNode root,int k){
    if(root == null){
        return 0;
    }
    if(k == 1){
        return 1;
    }
    return getKSize(root.left,k-1)+getKSize(root.right,k-1);
}

 

2.4.7 获取二叉树的高度

/**
 * 二叉树的最大高度
 * @param root 根节点
 * @return 返回值
 */
public int getHead(BTNode root){
    if(root == null){
        return 0;
    }
    return Math.max(getHead(root.left)+1,getHead(root.right)+1);
}

2.4.8 层序遍历

思路:

1.定义队列和辅助节点cur,将root赋值给cur

2.如果cur不为空,打印该节点的value值并将该节点入队列

3.从队列中poll出队头元素赋值给cur

4.如果cur节点的左节点不为空,将该节点入队列并打印该节点的value值

5.如果cur节点的右节点不为空,将给节点入队列并打印该节点的value值

6.重复3,4,5 直到队列为空为止

图解:

 

 

/**
 * 二叉树的层序遍历
 *
 * @param root 根节点
 */
public void LevelOrder(BTNode root) {
    BTNode cur = root;
    Queue<BTNode> queue = new ArrayDeque<>();

    if (cur != null) {
        queue.add(root);
        System.out.println(root.value);
    }

    while (!queue.isEmpty()) {
        cur = queue.poll();
        if (cur.left != null) {
            queue.add(cur.left);
            System.out.println(cur.left.value);
        }
        if (cur.right != null) {
            queue.add(cur.right);
            System.out.println(cur.right.value);
        }
    }
}

2.4.9 判断一棵树是否是完全二叉树

 还记得什么是完全二叉树?

 只可意会,不可言传!

思路分析:

在上面层序遍历的思想上加以改进即可

1.定义队列和辅助节点cur,将root赋值给cur

2.如果cur不为空,打印该节点的value值并将该节点入队列

3.从队列中poll出队头元素赋值给cur

4.判断当前cur是否为空

5.cur为空 循环出队列 将出队列的值赋值给cur ,在队列非空之前,只要cur有一次为非空,即为非完全二叉树

6.cur不为空 将cur节点的左右节点都添加到队列中,不用关心左右节点是否为空

7.重复3,4,5 直到队列为空为止

图解:

好好想想是不是这样的

完全二叉树图解

 

代码实现:

/**
 * 判断一个二叉树是否是完全二叉树
 *
 * @param root 二叉树根节点
 * @return 返回值为布尔, 代表是否是完全二叉树
 */
public Boolean IsCompleteBinaryTree(BTNode root) {
    BTNode cur = root;
    Queue<BTNode> queue = new LinkedList<>();

    if (cur != null) {
        queue.add(root);
    }

    while (true) {
        cur = queue.poll();
        if(cur == null){
            while(!queue.isEmpty()){
                cur = queue.poll();
                if(cur != null){
                    return false;
                }
            }
            return true;
        }else{
            queue.add(cur.left);
            queue.add(cur.right);
        }
    }

}


总结

树的知识远远不止这些,只能说是基础吧,大家好好消化,尤其是二叉树方面的代码一定要搞清楚

往后面试说不定就考到了。

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

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

相关文章

高云FPGA系列教程(7):ARM GPIO外部中断

文章目录 [toc]GPIO中断简介FPGA配置常用函数MCU程序设计工程下载 本文是高云FPGA系列教程的第7篇文章。 本篇文章介绍片上ARM Cortex-M3硬核处理器GPIO外部的使用&#xff0c;演示按键中断方式来控制LED亮灭&#xff0c;基于TangNano 4K开发板。 参考文档&#xff1a;Gowin_E…

go学习之函数知识

函数 文章目录 函数1.函数入门(1)为什么需要函数&#xff1f;(2)什么是函数&#xff1a;2.包3.函数的调用机制通俗理解调用过程&#xff1a;return语句递归调用 4.函数注意事项和细节讨论5.init函数6.匿名函数7.闭包8.defer9.函数参数的传递方式10.字符串中常用的函数11.时间和…

JVM中的java同步互斥工具应用演示及设计分析

1.火车站售票系统仿真 某火车站目前正在出售火车票&#xff0c;共有50张票&#xff0c;而它有3个售票窗口同时售票&#xff0c;下面设计了一个程序模拟该火车站售票&#xff0c;通过实现Runnable接口实现&#xff08;模拟网络延迟&#xff09;。 伪代码&#xff1a; Ticket类…

Java代码质量评估工具

概述 Java代码的质量评估主要包括代码的可维护性、健壮性、以及在运行时能达到既定的性能目标&#xff0c;可维护性主要包括代码的可读性、在关键的代码上提供详细注释、在设计类、方法以及代码逻辑时符合设定的编码规范&#xff0c;健壮性主要包括编写代码时应使用常用的设计…

【JAVA-Day26】数组解析:什么是数组?如何定义?

数组解析&#xff1a;什么是数组&#xff1f;如何定义&#xff1f; 数组解析&#xff1a;什么是数组&#xff1f;如何定义&#xff1f;摘要一、什么是数组数组的特性&#xff1a;不同类型的数组&#xff1a;数组的应用场景&#xff1a;数组的限制和挑战&#xff1a; 二、如何定…

【论文阅读 07】Anomaly region detection and localization in metal surface inspection

比较老的一篇论文&#xff0c;金属表面检测中的异常区域检测与定位 总结&#xff1a;提出了一个找模板图的方法&#xff0c;使用SIFT做特征提取&#xff0c;姿态估计看差异有哪些&#xff0c;Hough聚类做描述符筛选&#xff0c;仿射变换可视化匹配图之间的关系&#xf…

【算法基础】数学知识

质数 质数的判定 866. 试除法判定质数 - AcWing题库 时间复杂度是logN #include<bits/stdc.h> using namespace std; int n; bool isprime(int x) {if(x<2) return false;for(int i2;i<x/i;i){if(x%i0) return false;}return true; } signed main() {cin>&g…

Git学习笔记1

任务要求&#xff1a; 1、使用git提交代码到仓库&#xff1b; 2、实现自动代码发布系统&#xff1b; 1、了解DevOps的发展历程和思想&#xff1b; 2、学会git版本控制&#xff1b; 3、会使用github公有仓库和gitlab私有仓库&#xff1b; 4、了解CI/CD&#xff1b; 5、使用…

svn(乌龟svn)和SVN-VS2022插件(visualsvn) 下载

下载地址: https://www.visualsvn.com/visualsvn/download/

Go的error接口

从本书的开始&#xff0c;我们就已经创建和使用过神秘的预定义error类型&#xff0c;而且没有解释它究竟是什么。实际上它就是interface类型&#xff0c;这个类型有一个返回错误信息的单一方法&#xff1a; type error interface { Error() string } 创建一个error最简单的方…

cutree 算法

传播 ​ 由于块与块之间具有参考关系&#xff0c;提升被参考块的质量&#xff0c;可以改善后续参考块的质量 ​ Pn1帧中CU0,1完全参考Pn的CU1,1。且Pn1帧中CU0,1块帧内预测和帧间预测的代价分别为 c x , y n 1 ( 0 , 0 ) c_{x,y}^{n1}(0,0) cx,yn1​(0,0)和 c x , y n 1 ( d…

vue获取本地缓存并转为json格式

场景 要求获取当前登录用户id&#xff0c;传入后台去筛选属于该用户的数据&#xff1b; 当前登录用户信息一般会在本地存储中&#xff0c;有些则是在session中&#xff0c;此处只对本地存储做讨论&#xff1b; 本地缓存的用法 1 存储数据 localStorage.setltem(userId,"…

【版本控制】Github和Gitlab同时使用ssh

前言 最近在使用 WSL 时会同时用到 GitHub和 Gitlab &#xff0c;因此与传统配置 ssh 方式有些不一样的地方&#xff0c;这里特别记录一下 本地生成公私密钥 首先确保把之前的 ssh 信息清除&#xff0c;也可以将整个 ~/.ssh 目录删除 rm -rf ~/.ssh/*我们分别生成 Github 和…

Bigemap如何添加谷歌历史影像

工具 Bigemap gis office地图软件 BIGEMAP GIS Office-全能版 Bigemap APP_卫星地图APP_高清卫星地图APP 很多粉丝私信都在问怎么才可以看到谷歌的历史影像&#xff0c;其实这个图源目前是没有对大陆网络ip进行开放&#xff0c;所以如果需要查看&#xff0c;也是需要看你当前…

阿里云产品试用系列-Serverless 应用引擎 SAE

Serverless 应用引擎 SAE&#xff08;Serverless App Engine&#xff09;是一个全托管、免运维、高弹性的通用 PaaS平台。SAE 支持 Spring Boot、Spring Cloud、Dubbo、HSF、Web 应用和 XXL-JOB、ElasticJob任务的全托管&#xff0c;零改造迁移、无门槛容器化、并提供了开源侧诸…

【JAVA-Day23】Java反射的五大神奇妙用,令人惊叹

Java反射的五大神奇妙用&#xff0c;令人惊叹 Java反射的五大神奇妙用&#xff0c;令人惊叹摘要引言一、什么是反射?一、什么是反射?1.1 为什么需要反射?1.1.1 动态加载类1.1.2 序列化和反序列化1.1.3 框架和库开发 1.2 反射基础 二、类2.1 类完整路径2.2 包路径2.3 类名2.4…

乐鑫科技全球首批支持蓝牙 Mesh Protocol 1.1 协议

乐鑫科技 (688018.SH) 非常高兴地宣布&#xff0c;其自研的蓝牙 Mesh 协议栈 ESP-BLE-MESH 现已支持最新蓝牙 Mesh Protocol 1.1 协议的全部功能&#xff0c;成为全球首批在蓝牙技术联盟 (Bluetooth SIG) 正式发布该协议之前支持该更新的公司之一。这意味着乐鑫在低功耗蓝牙无线…

vue 封装element公共组件 +后端联调

首先封装的是一个分页&#xff0c;也是项目组封装公共组件最多之一 1-1创建一个新的页面放分页功能 <template><div><el-pagination size-change"handleSizeChange" current-change"handleCurrentChange" :current-page"currentPage…

掷骰子的多线程应用程序2基于互斥量的线程同步(复现《Qt C++6.0》)

说明&#xff1a;在复现过程中出现两点问题&#xff08;1&#xff09;run()函数中对m_diceValued的赋值&#xff08;2&#xff09;do_timeOut()函数中没有对m_seq、m_diceValued进行定义。修改后的复现程序如下所示&#xff1a; 主线程&#xff1a; .h #pragma once#include…

python excel复制数据保留单元格格式(.xls.xlsx)

最近帮朋友开发一个数据excel根据条件动态过率的功能.读取生成用pandas很方便,但是这里有一点比较麻烦的是得保留原来的单元格格式.这点操作起来就要麻烦一点了.下面总结了.xlsx和.xls处理 1.xlsx 文件处理 xlsx文件处理可以使用openpyxl库进行处理,比较简单,流程如下 1.获取…