11. 数据结构之二叉树

news2024/11/24 10:25:34

前言

上一节,简单概述了树这种数据结构,以及树结构向下,具有某些一些特征的树,比如二叉树,B树,B+树,堆等。其中,二叉树是一个很重要的模块。也是在一些技术面试中,可能会问到的问题。本节,我们就二叉树,做详细介绍。

1. 存储

二叉树是一个逻辑结构底层可以用数组或者链表存储

1.1 数组存储

使用数组存储时,会按照层级顺序把二叉树的节点放到数组中对应的位置上。如果某一个节点的左孩子或右孩子空缺,则数组的相应位置也空出来。
在这里插入图片描述
由此,可以得出结论:在用数组存储时,

  1. 一个父节点的下标是n,那么它的左孩子节点下标就是2×n+1、右孩子节点下标就是2x(n+1)
  2. 对于一个稀疏的二叉树(孩子不满)来说,用数组表示法是非常浪费空间的
  3. 所以二叉树一般用链表存储实现。(二叉堆除外,因为二叉堆是一个完全二叉树,节点基本都是满的

1.2 链表存储

在使用链表存储时,二叉树的每个节点至少包含三部分:

  1. 存储数据的data变量
  2. 指向左孩子的left指针
  3. 指向右孩子的right指针

如下图所示:
在这里插入图片描述

2. 遍历

二叉树,是典型的非线性数据结构,遍历时需要把非线性关联的节点转化成一个线性的序列,以不同的方式来遍历,遍历出的序列顺序也不同。

2.1 深度优先遍历

所谓深度优先,就是偏向于纵深,“一头扎到底”的访问方式。

2.1.1 前序遍历

二叉树的前序遍历,输出顺序是根节点、左子树、右子树
在这里插入图片描述
步骤如下:

  1. 首先输出的是根节点1
  2. 由于根节点1存在左孩子,输出左孩子节点2
  3. 由于节点2也存在左孩子,输出左孩子节点4
  4. 节点4既没有左孩子,也没有右孩子,那么回到节点2,输出节点2的右孩子节点5
  5. 节点5既没有左孩子,也没有右孩子,那么回到节点1,输出节点1的右孩子节点3
  6. 节点3没有左孩子,但是有右孩子,因此输出节点3的右孩子节点6
    到此为止,所有的节点都遍历输出完毕

2.1.2 中序遍历

二叉树的中序遍历,输出顺序是左子树、根节点、右子树。
在这里插入图片描述
步骤如下:

  1. 首先访问根节点的左孩子,如果这个左孩子还拥有左孩子,则继续深入访问下去,一直找到不再有左孩子 的节点,并输出该节点。显然,第一个没有左孩子的节点是节点4
  2. 依照中序遍历的次序,接下来输出节点4的父节点2
  3. 再输出节点2的右孩子节点5
  4. 以节点2为根的左子树已经输出完毕,这时再输出整个二叉树的根节点1
  5. 由于节点3没有左孩子,所以直接输出根节点1的右孩子节点3
  6. 最后输出节点3的右孩子节点6
    到此为止,所有的节点都遍历输出完毕

2.1.3 后序遍历

二叉树的后序遍历,输出顺序是左子树、右子树、根节点
在这里插入图片描述
步骤如下:

  1. 首先访问根节点的左孩子,如果这个左孩子还拥有左孩子,则继续深入访问下去,一直找到不再有左孩子 的节点,并输出该节点。显然,第一个没有左孩子的节点是节点4
  2. 输出右节点5
  3. 输出节点4的父节点2
  4. 以节点2为根的左子树已经输出完毕,这时再输出整个二叉树的右子树
  5. 访问根节点的右孩子,如果这个右孩子拥有左孩子,则继续深入访问下去,一直找到不再有左
    孩子 的节点,如果没有左孩子则找右孩子,并输出该节点6
  6. 输出节点6的父节点3
    到此为止,所有的节点都遍历输出完毕。

2.2 广度优先遍历

也叫层序遍历,顾名思义,就是二叉树按照从根节点到叶子节点的层次关系,一层一层横向遍历各个节点。
在这里插入图片描述
二叉树同一层次的节点之间是没有直接关联的,利用队列可以实现

2.3 遍历代码实现

2.3.1 定义树节点

package org.wanlong.tree;

/**
 * @author wanlong
 * @version 1.0
 * @description: 树节点定义
 * @date 2023/6/1 11:22
 */
public class TreeNode<T> {
    //数据
    T data;
    //左孩子
    TreeNode left;
    //右孩子
    TreeNode right;


    public TreeNode(T data) {
        this.data = data;
    }
}

2.3.2 定义树节点维护方法

package org.wanlong.tree;

/**
 * @author wanlong
 * @version 1.0
 * @description: 二叉树
 * @date 2023/6/1 11:24
 */
public class BinaryTree {

    TreeNode root;

    public void insertNode(int data) {
        root = insert(root, data);
    }

    /**
     * @param node: 基准节点
     * @param data: 待插入数据
     * @return org.wanlong.tree.TreeNode
     * @Description:往一个节点下面插入data数据
     * @Author: wanlong
     * @Date: 2023/6/1 11:28
     **/
    public TreeNode insert(TreeNode<Integer> node, Integer data) {
        //如果基准节点为空,创建新的节点插入
        if (node == null) {
            return new TreeNode(data);
        }
        //如果待插入数据小于当前节点,插入左子树
        if (data < node.data) {
            //递归确定插入左子树的位置,插入后,返回左子树指针
            node.left = insert(node.left, data);
            //如果待插入节点大于当前节点,插入右子树
        } else if (data > node.data) {
            node.right = insert(node.right, data);
        } else {
            node.data = data;
        }
        return node;
    }
}

2.3.3 前序遍历代码实现

/**
 * @param node:
 * @return void
 * @Description: 前序遍历节点 先根,再左再右
 * @Author: wanlong
 * @Date: 2023/6/1 11:38
 **/
public void preOrder(TreeNode node) {
    if (node == null) {
        return;
    }
    System.out.println(node.data);
    preOrder(node.left);
    preOrder(node.right);
}

2.3.4 中序遍历代码实现

/**
 * @param node:
 * @return void
 * @Description:中序遍历 先左 再根 再右
 * @Author: wanlong
 * @Date: 2023/6/1 11:41
 **/
public void middleOrder(TreeNode node) {
    if (node == null) {
        return;
    }
    middleOrder(node.left);
    System.out.println(node.data);
    middleOrder(node.right);
}

2.3.5 后序遍历代码实现

/**
 * @param node:
 * @return void
 * @Description:后序遍历 先左,再右,再根
 * @Author: wanlong
 * @Date: 2023/6/1 15:21
 **/
public void postOrder(TreeNode node) {
    if (node == null) {
        return;
    }
    postOrder(node.left);
    postOrder(node.right);
    System.out.println(node.data);
}

2.3.6 广度优先遍历代码实现

广度优先遍历可用节点入队出队的方式便捷实现,具体代码实现如下

/**
 * @Description: 广度优先遍历
 * @Author: wanlong
 * @Date: 2023/6/1 15:29
 * @param root:
 * @return void
 **/
public void wideOrder(TreeNode root){
    //广度优先遍历可用队列出队入队的方式快速实现
    LinkedList<TreeNode> queue = new LinkedList<>();
    //根节点入队
    queue.offer(root);
    while (!queue.isEmpty()){
        //队列头节点出队
        TreeNode node = queue.poll();
        //打印数据
        System.out.println(node.data);
        //左右节点入队
        if (node.left!=null){
            queue.offer(node.left);
        }
        if (node.right!=null){
            queue.offer(node.right);
        }
    }
}

2.3.7 遍历结果测试

package org.wanlong.tree;

import org.junit.BeforeClass;
import org.junit.Test;

/**
 * @author wanlong
 * @version 1.0
 * @description: 测试树的遍历
 * @date 2023/6/1 15:15
 */
public class Client {

    static BinaryTree btt = new BinaryTree();

    @BeforeClass
    public static void init() {
        btt.insertNode(10);
        btt.insertNode(8);
        btt.insertNode(11);
        btt.insertNode(7);
        btt.insertNode(9);
        btt.insertNode(12);

    }

    @Test
    public void testpre() {
        btt.preOrder(btt.root);
        //10
        //8
        //7
        //9
        //11
        //12
    }

    @Test
    public void testMiddle() {
        btt.middleOrder(btt.root);
        //7
        //8
        //9
        //10
        //11
        //12
    }

    @Test
    public void testpost() {
        btt.postOrder(btt.root);
        //7
        //9
        //8
        //12
        //11
        //10
    }

    @Test
    public void testwide(){
        btt.wideOrder(btt.root);
    }
    //10
    //8
    //11
    //7
    //9
    //12
}

以上,本人菜鸟一枚,如有错误,请不吝指正。

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

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

相关文章

【Vue】学习笔记-Vuex

Vuex 理解VuexVuex是什么什么时候使用VuexVuex 工作原理图求和案例使用纯vue编写 搭建Vuex环境使用Vuex编写求和案例getters配置项四个map方法的使用多组件共享数据案例模块化命名空间 理解Vuex Vuex是什么 概念&#xff1a;专门在vue中实现集中式状态(数据) 管理的一个vue插…

基于P-Tuningv2轻量微调和推理chatglm

类ChatGPT的部署与微调(下)&#xff1a;从GLM、ChatGLM到MOSS、ChatDoctor、可商用_v_JULY_v的博客-CSDN博客随着『GPT4多模态/Microsoft 365 Copilot/Github Copilot X/ChatGPT插件』的推出&#xff0c;绝大部分公司的技术 产品 服务&#xff0c;以及绝大部分人的工作都将被革…

【CMake 入门与进阶(2)】CMake编译设置——多个源文件编译及生成库文件(附代码)

多个源文件 上篇我们学习了单个源文件的cmake 的编译&#xff0c;不过一个源文件的例子似乎没什么意思&#xff0c;我们再加入一个hello.h 头文件和 hello.c 源文件。在 hello.c 文件中 定义了一个函数 hello&#xff0c;然后在 main.c 源文件中将会调用该函数&#xff…

客服都要下岗了? 当ChatGPT遇见私有数据,秒变AI智能客服!

用ChatGPT搭建基于私有数据的WorkPlus AI客服机器人这个想法&#xff0c;源于WorkPlus售前工作需求。在ChatGPT之前&#xff0c;其实对话式AI一直在被广泛使用在客服场景&#xff0c;只不过不大智能而已。比如你应该看到不少电商客服产品&#xff0c;就有类似的功能&#xff0c…

车站信息管理系统(面向对象程序设计python版)

一、基本概述 1.项目背景 随着大数据时代的发展,大数据抓取了人们最想要的信息,数据查询能帮助用户获取更有用的信息,让每个人都能享受到大数据带给生活的高效和便捷。 2.设计目的 为了大大缩减人们出行选择站点所需时间,为了让人们在陌生地区,在对当地交通不熟的情况…

Redis数据类型之(哈希Hash和集合Set)

Redis数据类型之&#xff08;哈希Hash和集合Set&#xff09; 一定注意看红色注意项。 哈希&#xff08;Hash&#xff09;: Redis hash 是一个 string 类型的 field&#xff08;字段&#xff09; 和 value&#xff08;值&#xff09; 的映射表&#xff0c;hash 特别适合用于存…

promethues 之PromQL数据类型介绍(二)

promethues 之PromQL数据类型介绍(二) 1、PromQL 介绍 PromQL是promethues 监控系统内置的一种查询语言&#xff0c;类似于MySQL的SQL语句&#xff0c;该语言仅用于读取数据。PromQL是我们学习Promethues最困难也是最重要的部分。当Promethues从系统和服务收集到指标数据时&…

PIP-Net:用于可解释图像分类的基于patch的直观原型

文章目录 PIP-Net: Patch-Based Intuitive Prototypes for Interpretable Image Classification摘要本文方法模型结构Self-Supervised Pre-Training of PrototypesTraining PIP-NetScoring Sheet ReasoningCompact Explanations 实验结果 PIP-Net: Patch-Based Intuitive Proto…

bug 记录 - 接口被重复调用,响应时长不同,结果被覆盖的问题

发现问题与调试过程 需求&#xff1a;输入框中输入关键字&#xff0c;根据关键字去调用接口&#xff0c;返回模糊查询的结果集合。问题&#xff1a;输入的关键字越少&#xff0c;接口响应时间越长。例如&#xff1a;输入“阿”&#xff0c;接口响应时间大概是 5 秒&#xff0c…

【计算机网络中ip概念总结】【平时我们说的ip 到底是什么】【计算机网络中 ip地址是什么】

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

【Linux】重定向dup

文章目录 前言重定向的原理dup函数添加重定向功能到myshell 前言 了解重定向之前需要明白文件描述符的工作规则&#xff0c;可以看这篇文章&#xff1a;文件系统 最关键的一点是&#xff1a;在进程中&#xff0c;在文件描述符表中&#xff0c;会将最小的、没有被使用的数组元…

vscode整合gitee

vscode需要下载的插件 第一个可以多仓库进行操作 第二个主要是用于仓库的管理和展示 vscode的gitee操作 1、按F1&#xff0c;搜索gitee 2、根据提示进行操作 标1的是第一个插件的操作 标2的是第二个插件的操作 绑定用户私钥 两个插件绑定私钥的方式不同&#xff0c; gitee的私…

这本数智平台白皮书讲透了大型企业数智化升级业务痛点

在以“升级企业数智化底座”为主题的2023用友BIP技术大会上&#xff0c;用友联合全球权威咨询机构IDC共同发布《建设数字中国 升级数智底座——企业数智化底座白皮书》&#xff0c;在这本数智平台白皮书里深入剖析了大型企业的数智化升级痛点。 大型企业普遍具有广域的业务覆盖…

六级备考15天|CET-6|翻译真题练习|北京大兴国际机场|9:15~10:20

目录 中文 英文 词汇 订正 解析 练习 中文 英文 词汇 put sth. into use 投入使用 距离south of地点 “...以南....公里处” construction 开工建设 the giant project 巨型工程 on the site …

LED显示屏驱动IC基本原理

LED显示屏驱动IC&#xff08;Integrated Circuit&#xff0c;集成电路&#xff09;是一种专门设计用于控制和驱动LED显示屏的电子元件。LED显示屏驱动IC的基本原理涉及到LED的电流控制、亮度调节、扫描控制和图像数据处理等方面。 以下是LED显示屏驱动IC的基本原理的详细说明&a…

只需简单几步,就能在报表工具FastReport .NET 中使用 RFID 标签

FastReport 是功能齐全的报表控件&#xff0c;可以帮助开发者可以快速并高效地为.NET&#xff0c;VCL&#xff0c;COM&#xff0c;ActiveX应用程序添加报表支持&#xff0c;由于其独特的编程原则&#xff0c;现在已经成为了Delphi平台最优秀的报表控件&#xff0c;支持将编程开…

喜讯丨计讯物联5G物联网数据网关TG463荣登2022年度中国物联网行业创新产品榜

近日&#xff0c;备受瞩目的2022‘物联之星’中国物联网产业年度榜单颁奖典礼在上海世博展览馆会场隆重举行。经由申报筛选、网络人气投票、专家评委投票等多重环节&#xff0c;计讯物联旗下5G物联网数据网关TG463荣登2022年度中国物联网行业创新产品榜。 作为中国物联网行业…

chatgpt赋能python:Python编写抽奖程序——让你的活动更加有趣

Python编写抽奖程序——让你的活动更加有趣 在现代社会中&#xff0c;抽奖活动已经成为了许多商家和组织吸引关注、增强互动的重要手段。而使用Python编写抽奖程序可以帮助我们更加方便地进行这一活动。本文将介绍Python编写抽奖程序的方法&#xff0c;以及如何在实际应用中优…

【强化学习原理+项目专栏】必看系列:单智能体、多智能体算法原理+项目实战、相关技巧(调参、画图等)、趣味项目实现、学术应用项目实现

【强化学习原理项目专栏】必看系列&#xff1a;单智能体、多智能体算法原理项目实战、相关技巧&#xff08;调参、画图等、趣味项目实现、学术应用项目实现 对于深度强化学习这块规划为&#xff1a; 基础单智能算法教学&#xff08;gym环境为主&#xff09;主流多智能算法教学…

Hive和Hadoop关系

Hive是基于Hadoop的一个数据仓库工具&#xff0c;用来进行数据提取、转化、加载&#xff0c;这是一种可以查询和分析存储在Hadoop中的大规模数据的机制。Hive数据仓库工具能将结构化的数据文件映射为一张数据库表&#xff0c;并提供SQL查询功能&#xff0c;能将SQL语句转变成Ma…