当前位置: 首页 > news >正文

【二叉树入门指南】链式结构的实现

【二叉树入门指南】链式结构的实现

  • 一、前置说明
  • 二、二叉树的遍历
      • 2.1前序遍历
      • 2.2中序遍历
      • 2.3 后序遍历
  • 三、以前序遍历为例,递归图解
  • 四、层序遍历
  • 五、节点个数以及高度等
      • 5.1 二叉树节点个数
      • 5.2二叉树叶子节点个数
      • 5.3 二叉树第k层节点个数
      • 5.4 二叉树查找值为x的节点
      • 5.5 二叉树的高度
  • 六、二叉树的创建和销毁
      • 6.1 构建二叉树
      • 6.2 二叉树的销毁
      • 6.3 判断二叉树是否为完全二叉树


在这里插入图片描述


一、前置说明

其他数据结构不同,二叉树的增删查改接口实现的意义不大(后续搜索树的增删查改才有意义)。普通初阶二叉树更重要的是学习控制结构,为后续的AVL树、红黑树等高级数据结构打下基础。同时大部分OJ题也出在此处。


二、二叉树的遍历

所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的节点进行相应的操作,并且每个节点只操作一次。访问结点所做的操作依赖于具体的应用问题。
 
在这里插入图片描述
按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历:

  • 前序遍历(Preorder Traversal 亦称先序遍历)——访问顺序:根节点—>左子树—>右子树
  • 中序遍历(Inorder Traversal)——访问顺序:左子树—>根节点—>右子树
  • 后序遍历(Postorder Traversal)——访问顺序:左子树—>右子树—>根节点

2.1前序遍历

【代码思路】:

  1. 若二叉树为空,则直接返回。
  2. 访问根节点。
  3. 递归遍历左子树,即调用前序遍历函数,传入左子树的根节点。
  4. 递归遍历右子树,即调用前序遍历函数,传入右子树的根节点

代码:

void PrevOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}printf("%d ", root->data);PrevOrder(root->left);PrevOrder(root->right);
}

2.2中序遍历

【代码思路】:

  1. 首先判断二叉树是否为空,若为空则直接返回。
  2. 对当前节点的左子树进行中序遍历,即递归调用中序遍历函数。
  3. 访问当前节点的值。
  4. 对当前节点的右子树进行中序遍历,即递归调用中序遍历函数。

代码:

void InOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}

2.3 后序遍历

【代码思路】:

  1. 判断当前节点是否为空,若为空则返回。
  2. 递归遍历当前节点的左子树。
  3. 递归遍历当前节点的右子树。
  4. 访问当前节点。

代码:

void PostOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->data);
}

三、以前序遍历为例,递归图解

前序遍历递归图解:


在这里插入图片描述


在这里插入图片描述
上述三种遍历结果:

  1. 前序遍历结果:1 2 3 4 5 6
  2. 中序遍历结果:3 2 1 5 4 6
  3. 后序遍历结果:3 2 5 6 4 1

四、层序遍历

层序遍历:除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
在这里插入图片描述
【代码思路】:(核心思想:上一层出时带下一层进队列,即根节点出栈时,根节点的孩子节点入栈)

  1. 首先将根节点入栈。
  2. 循环进行以下操作,直到栈为空。
    。弹出栈顶元素,并将其值输出;
    。如果该节点有右子节点,则将右子节点入栈。
    。 如果该节点有左子节点,则将左子节点入栈

栈相关代码自行查看:栈和队列代码实现

代码:

void LevelOrder(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);printf("%d ", front->data);if(front->left)QueuePush(&q, front->left);if (front->right)QueuePush(&q, front->right);}printf("\n");QueueDestroy(&q);
}

五、节点个数以及高度等

5.1 二叉树节点个数

【代码思路】:

  1. 如果二叉树为空,则节点个数为0。
  2. 否则,节点个数等于根节点的个数加上左子树的节点个数和右子树的节点个数。
  3. 递归计算左子树的节点个数。
  4. 递归计算右子树的节点个数。
  5. 返回根节点个数加上左子树和右子树的节点个数。

代码:

int BinaryTreeSize(BTNode* root)
{if (root == NULL){return 0;}return  BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

5.2二叉树叶子节点个数

【代码思路】:

  1. 判断根节点是否为空,若为空,则返回0。
  2. 判断根节点的左右子树是否为空,若都为空,则表示根节点是叶子节点,返回1。
  3. 通过递归分别计算左子树和右子树的叶子节点个数,并返回左子树和右子树的叶子节点个数之和。

代码:

int BinaryTreeLeafSize(BTNode* root)
{if (root == NULL){return 0;}if (root->left == NULL && root->right == NULL){return 1;}return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

5.3 二叉树第k层节点个数

【代码思路】:

  1. 判断二叉树是否为空,如果是则返回0。
  2. 判断k是否等于1,如果是则返回1,表示当前层为第k层,只有一个节点。
  3. 如果以上条件都不满足,则递归计算二叉树的左子树和右子树的第k-1层节点个数,然后将左右子树的第k-1层节点个数相加,即为二叉树第k层节点个数。

代码:

int BinaryTreeLevelKSize(BTNode* root, int k)
{assert(k > 0);if (root == NULL){return 0;}if (k == 1){return 1;}return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

5.4 二叉树查找值为x的节点

【代码思路】:

  1. 如果当前节点为空,则返回空。
  2. 如果当前节点的值等于x,则返回当前节点。
  3. 否则,递归查找左子树,如果找到则返回左子树中的节点。
  4. 否则,递归查找右子树,如果找到则返回右子树中的节点。

代码:

BTNode* BTreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->data == x)return root;BTNode* ret1 = BTreeFind(root->left, x);if (ret1)return ret1;BTNode* ret2 = BTreeFind(root->right, x);if (ret2)return ret2;return NULL;
}

5.5 二叉树的高度

【代码思路】:

  1. 如果树为空树,则高度为0。
  2. 如果树不为空树,则高度为左子树的高度和右子树的高度中的较大值加1。
  3. 递归地计算左子树和右子树的高度,并取较大值。
  4. 返回左子树和右子树高度的较大值加1。

代码:

int BinaryTreeHeight(BTNode* root)
{if (root == NULL){return 0;}int LeftHeight = BinaryTreeHeight(root->left);int RightHeight = BinaryTreeHeight(root->right);return LeftHeight > RightHeight ? LeftHeight + 1 : RightHeight + 1;
}

六、二叉树的创建和销毁

6.1 构建二叉树

Tips: 构建二叉树的方式有很多, 这里我们通过前序遍组"ABD##E#H##CF##G##"构建二叉树。(‘#’表示空树
【代码思路】:

  1. 如果节点为“#”表示空,返回空。
  2. 遍历创建左子树,并和根节点链接。
  3. 遍历创建右子树,并和根节点链接。
  4. 返回根节点

代码:

typedef int BTDataType;
typedef struct BinaryTreeNode//结构体类型
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;//创建节点
BTNode* BuyNode(BTDataType x)
{BTNode* Node = (BTNode*)malloc(sizeof(BTNode));if (Node == NULL){perror("malloc fail");exit(-1);}Node->data = x;Node->left = NULL;Node->right = NULL;return Node;
}//先序创建二叉树
BTNode* createrroot(char* a, int* pi)
{if (a[*pi] == '#'){(*pi)++;return NULL;}BTNode* root = BuyNode(a[*pi]);(*pi)++;root->left = createrroot(a, pi);root->right = createrroot(a, pi);return root;
}

6.2 二叉树的销毁

【代码思路】:

  1. 从根节点开始,递归地销毁左子树。
  2. 从根节点开始,递归地销毁右子树。
  3. 将根节点从内存中删除。

代码:

void BinaryTreeDestroy(BTNode* root)
{if (root == NULL)return;BinaryTreeDestory(root->left);BinaryTreeDestory(root->right);free(root);
}

6.3 判断二叉树是否为完全二叉树

(博主数据结构初阶是用C语言来实现的,所以此处直接栈代码从博主代码仓库中拷贝过来的,读者可以用其他语言来实现,大同小异)

【代码思路】:

  1. 遍历二叉树,使用层次遍历的方式,从根节点开始,逐层遍历每个节点。
  2. 当遇到第一颗空树时停止遍历。
  3. 从第一颗空树开始,后续节点如果有非空就不是完全二叉树,否则为完全二叉树。

栈相关代码自行查看:栈和队列代码实现
代码:

int BinaryTreeComplete(BTNode* root)
{Que q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);//遇空就跳过if (front==NULL){break;}QueuePush(&q, root->left);QueuePush(&q, root->right);}//检查后续节点是否有非空//有非空就不是完全二叉树while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}

在这里插入图片描述
在这里插入图片描述
【数据结构入门指南】二叉树顺序结构: 堆及实现(全程配图,非常经典)

相关文章:

【二叉树入门指南】链式结构的实现

【二叉树入门指南】链式结构的实现 一、前置说明二、二叉树的遍历2.1前序遍历2.2中序遍历2.3 后序遍历 三、以前序遍历为例,递归图解四、层序遍历五、节点个数以及高度等5.1 二叉树节点个数5.2二叉树叶子节点个数5.3 二叉树第k层节点个数5.4 二叉树查找值为x的节点5…...

【位运算】算法实战

文章目录 一、算法原理常见的位运算总结 二、算法实战1. leetcode面试题01.01. 判断字符是否唯一2. leetcode268 丢失的数字3. leetcode371 两整数之和4. leetcode004 只出现一次的数字II5. leetcode面试题17.19. 消失的两个数字 三、总结 一、算法原理 计算机中的数据都以二进…...

C++构建系统

收集C构建系统(2023): 跟我一起写Makefile (PDF重制版)CMake tutorialConan, software package manager for C and C developersvcpkg-repovcpkgGoogle Bazel Build System { Fast, Correct } — Choose twoGN gn_quick_start当前Chromium构建系统 GYP Generate You…...

“深入探索JVM内部机制:理解Java虚拟机的运行原理“

标题:深入探索JVM内部机制:理解Java虚拟机的运行原理 摘要:本篇博客将深入探索Java虚拟机(JVM)的内部机制,帮助读者理解JVM的运行原理。我们将介绍JVM的组成结构,包括类加载器、运行时数据区域…...

java八股文面试[JVM]——双亲委派模型

1.当AppClassLoader去加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委托给父加载器ExtClassLoader去完成。 2.当ExtClassLoader去加载一个class时,它首先也不会去尝试加载这个类,而是把类加载请求委托给父加载…...

NLP与大模型主题全国师资培训班落地,飞桨持续赋能AI人才培养

为了推动大模型及人工智能相关专业人员的培养,8月11日-8月13日,由中国计算机学会主办、机械工业出版社、北京航空航天大学、百度飞桨联合承办 “CCF群星计划之文心高校行- NLP与大模型”主题师资培训班(以下简称培训班)在北京天信…...

Jupyter Notebook 配置根目录

注:本文是在 Windows 10 上配置 Jupyter Notebook 打开的默认根目录,Linux 同。 步骤一:创建 Jupyter Notebook 配置文件 使用以下命令创建 Jupyter Notebook 配置文件(如果尚未创建): jupyter notebook …...

算法 位运算

文章目录 一、&&#xff08;按位与&#xff09;运算符二、|&#xff08;按位或&#xff09;运算符三、^&#xff08;异或&#xff09;运算符四、~&#xff08;取反&#xff09;运算符五、<<&#xff08;左移&#xff09;运算符六、>>&#xff08;右移&#xff…...

Linux 虚拟机常用命令

一、文件/文件夹管理 1. ls命令 就是 list 的缩写&#xff0c;通过 ls 命令不仅可以查看 linux 文件夹包含的文件&#xff0c;而且可以查看文件权限(包括目录、文件夹、文件权限)查看目录信息等等。 ls -a 列出目录所有文件&#xff0c;包含以.开始的隐藏文件ls -A 列出除.…...

解决抖音semi-ui的Input无法获取到onChange事件

最近在使用semi-ui框架的Input实现一个上传文件功能时遇到了坑&#xff0c;就是无法获取到onChange事件&#xff0c;通过console查看只是拿到了一个文件名。但若是把<Input>换成原生的<input>&#xff0c;就可以正常获取到事件。仔细看了下官方文档&#xff0c;发现…...

免费的png打包plist工具CppTextu,一款把若干资源图片拼接为一张大图的免费工具

经常做游戏打包贴图的都知道&#xff0c;要把图片打包为一张或多张大图&#xff0c;要使用打包工具TexturePacker。 TexturePacker官方版可以直接导入PSD、SWF、PNG、BMP等常见的图片格式&#xff0c;主要用于网页、游戏和动画的制作&#xff0c;它可以将多个小图片汇聚成一个…...

深层次分析字符数组和字符串的区别是什么?

前言 &#xff08;1&#xff09;休闲时刻刷B站&#xff0c;看到一个卖课的&#xff0c;发视频问&#xff0c;char arr1[]{‘H’,‘E’,‘L’,‘L’,‘O’};和char arr2[]“HELLO”;区别是什么。 &#xff08;2&#xff09;看那个卖课博主一顿分析&#xff0c;最后成功得出&…...

Redis 的主从复制、哨兵模式、集群脑裂

主从复制 主从复制是 Redis 高可用服务最基础的保证&#xff0c;将一台 Redis 主服务器&#xff0c;同步数据到多台 Redis 从服务器上&#xff0c;即一主多从的模式&#xff0c;且主从服务器之间采用的是「读写分离」的方式。 主服务器可以进行读写操作&#xff0c;当发生写操…...

Pycharm通过SSH配置centos上Spark环境

直接在shell进行pyspark进行编程&#xff0c;程序没有办法写得太长&#xff0c;而且我们希望能够实现一个及时给出结果的编程环境&#xff0c;可以使用pycharm连接centos上的spark&#xff0c;进行本地编程&#xff0c;同步到centos系统中运行程序&#xff0c;并把结果返回pych…...

leetcode做题笔记98. 验证二叉搜索树

给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。 思路一&#xff1a;递归 …...

C# 中Lambda中的的匿名函数

/// <summary>/// 根据设备号&#xff0c;获取故障列表/// </summary>/// <param name"scanCode">主键</param>/// <returns></returns>[HttpGet]public async Task<IActionResult> GetItemPageList(string scanCode){//v…...

铰接式车辆的横向动力学仿真提供车辆模型研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

Ubuntu20 安装 libreoffice

1 更新apt-get sudo apt-get update2 安装jdk 查看jdk安装情况 Command java not found, but can be installed with:sudo apt install default-jre # version 2:1.11-72, or sudo apt install openjdk-11-jre-headless # version 11.0.138-0ubuntu1~20.04 sud…...

HTTP协议(JavaEE初阶系列15)

目录 前言&#xff1a; 1.HTTP协议 1.1HTTP协议是什么 1.2HTTP协议的报文格式 1.2.1抓包工具的使用 1.2.2HTTP请求 1.2.3HTTP响应 2.HTTP请求 2.1首行的组成 2.2.1URL的组成 2.2认识“方法”&#xff08;method&#xff09; 2.2.1GET方法 2.2.2POST方法 2.2.3GET…...

机器学习基础10-审查回归算法(基于波士顿房价的数据集)

上一节介绍了如何审查分类算法&#xff0c;并介绍了六种不同的分类算法&#xff0c;还 用同一个数据集按照相同的方式对它们做了审查&#xff0c;本章将用相同的方式对回归算法进行审查。 在本节将学到&#xff1a; 如何审查机器学习的回归算法。如何审查四种线性分类算法。如…...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

第八部分:阶段项目 6:构建 React 前端应用

现在&#xff0c;是时候将你学到的 React 基础知识付诸实践&#xff0c;构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段&#xff0c;你可以先使用模拟数据&#xff0c;或者如果你的后端 API&#xff08;阶段项目 5&#xff09;已经搭建好&#xff0c;可以直接连…...