【数据结构】详解二叉树及其操作

无论你觉得自己多么的了不起,也永远有人比你更强。💓💓💓

目录

  ✨说在前面

🍋知识点一:二叉树的遍历

 • 🌰1.创建一棵二叉树

• 🌰2.二叉树的遍历

•🔥前序遍历

•🔥中序遍历

•🔥后序遍历

•🔥层序遍历

•🔥给出两种遍历如何求二叉树?

🍋知识点二:二叉树基本方法

 • 🌰1.二叉树节点个数

• 🌰2.二叉树叶子节点个数

• 🌰3.二叉树第k层节点个数

• 🌰4.二叉树的高度

• 🌰5.查找值为x的节点

• 🌰6.判断是否为完全二叉树

• 🌰7.二叉树的销毁

• ✨SumUp结语


  ✨说在前面

亲爱的读者们大家好!💖💖💖,我们又见面了,经过上一篇章中“堆”的学习,大家已经了解了树的基本结构。但是,堆只是树中特殊的一种数据结构,并且是基于树的一种数据结构。

今天我们将要学习它更加抽象的一面,即二叉树,那什么是二叉树,他们又是用什么来实现,又有什么作用呢?我们今天就详细剖析二叉树这一的数据结构吧~

在上一篇文章中,为了引入堆,也很清晰地介绍了树和二叉树的概念和性质,忘记的小伙伴可以去看看。

  👇👇👇
💘💘💘知识连线时刻(直接点击即可)

  🎉🎉🎉复习回顾🎉🎉🎉

         【数据结构】详解二叉树之堆

  博主主页传送门:愿天垂怜的博客

 

🍋知识点一:二叉树的遍历

 • 🌰1.创建一棵二叉树

在学习二叉树的基本操作之前,我们首先需要创建一棵二叉树,然后才能学习其相关的基本操作。但是由于现在我们知识有限,先手动创建一个二叉树一遍快速进入二叉树操作的学习,等以后我们再回过头来学习它真正的创建方式。

比如我们要创建如下的一棵二叉树:

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>//创建二叉树的数据结构
typedef int BTDatatype;typedef struct BinaryTreeNode
{BTDatatype data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;//创建二叉树的节点
static BTNode* BuyNode(BTDatatype x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL){perror("malloc operation failed");exit(1);}node->data = x;node->left = node->right = NULL;return node;
}//手动创建二叉树
BTNode* CreateBinaryTree()
{BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;return node1;
}
注意:上面的代码不是创建二叉树的真正的方式,真正的二叉树是递归定义的,因此后序基本操作

    

• 🌰2.二叉树的遍历

学习二叉树结构,最简单的方式就是遍历。所谓二叉树遍历1(Traversal)是按照某种特定的规则,依次堆二叉树中的节点进行相应的操作,使得每个节点只操作依次。访问节点所做的操作依赖与具体的应用问题。

遍历是二叉树上最重要的运算之一,也是二叉树上进行其他运算的基础。

按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历;

🔥前序遍历(Prevorder Traversal)——访问根节点的操作发生在遍历其左右子树之前。

🔥中序遍历(Inorder Traversal)——访问根节点的操作发生在遍历其左右子树之中(间)。

🔥后序遍历(Postorder Traversal)——访问根节点的操作发生在遍历其左右子树之后。

由于被访问的节点必然是某子树的根,所以N(Node)、L(Left subtree)、R(Right subtree)又可以解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先跟遍历、中根遍历和后根遍历。 

•🔥前序遍历

对于以下这一棵二叉树:

我们如果按照访问根节点的操作发生在遍历其左右子树之前,那么所能得到这样的遍历顺序:1,2,3,4,5,6,这样的遍历称之为前序遍历。对于这样一棵树,我们先访问左子树,再访问根,最后访问右子树,而左子树和右子树中又是按照根——左子树——右子树的顺序遍历,以此往复,直到遍历完成。

代码如下:

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

上面代码完成了二叉树以前序遍历的方式打印每个节点中的值。.

•🔥中序遍历

对于以下这一棵二叉树:

我们如果按照访问根节点的操作发生在遍历其左右子树之中(间),那么所能得到这样的遍历顺序:3,2,1,5,4,6,这样的遍历称之为中序遍历。对于这样一棵树,我们先访问根,再访问左子树,最后访问右子树,而左子树和右子树中又是按照左子树——根——右子树的顺序遍历,以此往复,直到遍历完成。 

代码如下:

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

 

•🔥后序遍历

 对于以下这一棵二叉树:

我们如果按照访问根节点的操作发生在遍历其左右子树之后,那么所能得到这样的遍历顺序:3,2,5,6,4,1,这样的遍历称之为后序遍历。对于这样一棵树,我们先访问左子树,再访问右子树,最后访问根,而左子树和右子树中又是按照左子树——右子树——根的顺序遍历,以此往复,直到遍历完成。 

代码如下:

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

 

•🔥层序遍历

除了先序遍历,中序遍历、后序遍历外,还可以对二叉树进行层序遍历,如下面这棵二叉树:

设二叉树的根节点 所在的层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第二层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的节点的过程就是层序遍历。

实现二叉树的层序遍历,我们需要借助另一数据结构——队列。我们需要将根节点入队列,再每删除一个节点时,进行需要的操作,并将它的左右子节点入队列即可。

代码如下:

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

 

•🔥给出两种遍历如何求二叉树?

我们经常会碰到以下这种题型:

这些题通常都是给出其中两种遍历序列(或给出层序遍历序列),求节解这棵二叉树或者它的其他序列 。我们以上面第2题为例,假设我们要求整棵二叉树:

前序遍历:E F H I G J K        中序遍历:H F I E J K G

1.前序遍历确定根

即前序遍历的第一个E即为整棵二叉树的根节点。

2.中序遍历分割左右子树

即在中序遍历中找到E,则E左边的H F I为左子树,右边的J K G为右子树。

由此我们得到一下分析:

 分析到这个地方,我们可以得到左子树不为空,那么前序遍历的第二个F就是左子树的根,进而可以从中序遍历中找到F,它的左边H就是左子树的左子树,右边I就是左子树的右子树。同理,左子树走完后的第一个为G,则G是右子树的根节点,在中序遍历中找到G,它的左边J K就是右子树的左子树,而右子树的右子树为空。那么J K同理可以分析出J为它的左子树,K是J的右子树,即整棵树为:

🍋知识点二:二叉树基本方法

 • 🌰1.二叉树节点个数

我们利用递归的思想,将大问题拆分成许多类似的小问题。二叉树的节点个数等于它左子树的节点个数加上它右子树的节点个数再加1(它自己),而左子树和右子树的节点数同样等于它的左、右子树节点数和它自己,递归到最后节点如果为空,数量为0即可。

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

    

• 🌰2.二叉树叶子节点个数

我们的思想还是不变,都是递归的思想。叶子节点指的是度为0的节点,所以我们要检查一个节点它的左右孩子节点是否为空,如果都为空,那么就是叶子节点,返回1;如果不都为空,就递归下去,等于它的左子树和右子树的叶子节点之和;如果本身就是空,那就是0。

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

    

• 🌰3.二叉树第k层节点个数

第k层的节点个数等于左右子树第k-1层的节点个数之和,同样递归下去,直到k=1,也就是第1层,那就直接返回1。特殊地,如果节点为空,返回0。

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

    

• 🌰4.二叉树的高度

二叉树的高度等于它左右子树高的那一棵子树的高度+1,我们可以记录左右子树的值再进行判断,也可以用fmax函数,如果数为空,返回0。fmax函数在头文件math.h中声明。

int TreeHeight(BTNode* root)
{if (root == NULL)return 0;/*int left = TreeHeight(root->left);int right = TreeHeight(root->right);return left > right ? right + 1 : left + 1;*/return fmax(TreeHeight(root->left), TreeHeight(root->right)) + 1;
}

注意:这里使用三目运算符会使性能大大降低,因为每次return都要更多次地计算子树的高度。

    

• 🌰5.查找值为x的节点

用递归的方式遍历整棵树,如果为空就直接return NULL,不为空判断值是否为x,不为x就继续往下递归,为x就返回。也就是看自己是不是x,不是就返回左子树的查找,左子树也没有就返回右子树的查找。

BTNode* TreeFind(BTNode* root, int x)
{if (root == NULL)return NULL;if (root->data == x)return root;BTNode* ret = TreeFind(root->left, x);if (ret)return ret;return TreeFind(root->right, x);
}

    

• 🌰6.判断是否为完全二叉树

这时我们依然需要借助队列来进行判断。我们的思路是:将数中的每一个节点按照层序遍历的方式入队列(空节点也入队列),如果进入队列的节点为空,那么就停止,去判断后面所剩下的节点是否都为空。如果都为空,那就是完全二叉树,如果后面有不为空的节点,就不是完全二叉树。

 

代码如下:

bool TreeComplete(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front == NULL){break;}QueuePush(&q, front->left);QueuePush(&q, front->right);}while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}

    

• 🌰7.二叉树的销毁

销毁儿茶俗话就比较简单了,依次释放左右节点再释放根1节点就可以了。

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

• ✨SumUp结语

到这里本篇文章的内容就结束了,二叉树比我们以往的数据结构更加抽象,相信大家看完本篇文章已经发现了,涉及到的实现方法不断用到了递归的思想。希望大家可以好好复习今天的内容,自己尝试写代码~

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

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

相关文章

提升自身的国际影响力-香港服务器托管的优势

随着全球化的不断深入&#xff0c;中国企业正以前所未有的速度走向世界舞台&#xff0c;不仅在全球市场上展现其竞争力&#xff0c;更在寻求通过技术创新和服务优化来提升自身的国际影响力。在这一过程中&#xff0c;服务器的选择与托管成为了一个至关重要的环节。特别是在香港…

基于SpringBoot实现验证码功能

目录 一 实现思路 二 代码实现 三 代码汇总 现在的登录都需要输入验证码用来检测是否是真人登录&#xff0c;所以验证码功能在现在是非常普遍的&#xff0c;那么接下来我们就基于springboot来实现验证码功能。 一 实现思路 今天我们介绍的是两种主流的验证码&#xff0c;一…

使用php adodb5连接人大金仓数据库

打开php中的pgsql扩展 extensionpgsql使用adodb5连接kingbase数据库 <?php include("adodb5/adodb.inc.php"); $fox_dbtype pgsql; $fox_host 192.168.1.66; $fox_user system; $fox_pwd 123456; $fox_dbname testkingbase; $fox_port 54321;$dbNewADOCo…

级联目标检测 vs 单阶段检测:深度学习中的猫鼠游戏

级联目标检测 vs 单阶段检测&#xff1a;深度学习中的猫鼠游戏 目标检测是计算机视觉领域的一个核心问题&#xff0c;其目的是在图像中识别和定位一个或多个目标。随着深度学习技术的发展&#xff0c;目标检测方法经历了从传统算法到基于深度学习的方法的转变。目前&#xff0…

【JavaScript】对象属性

JS 对象的可枚举性指的是对象的某些属性是否可以被 JSON.stringify()、 for…in 循环、Object.keys()、Object.values() 和 Object.entries() ⽅法枚举到。 每个对象属性都有⼀个名字和一个属性描述符&#xff0c;这个属性描述符⾥⾯包括了该属性的许多特性&#xff0c;如可枚…

大数据技术--实验01-Hadoop的安装与使用【实测可行】

使用下面表中的软件版本进行配置&#xff1a; 准备好后&#xff0c;按照下面的步骤进行配置。 配置VMware网络 在VMWare主界面&#xff0c;点击“编辑”>“虚拟网络编辑”菜单进入虚拟网卡参数设置界面。选择VMnet8条目&#xff0c;点击“NAT设置”按钮后可以看到我们的VM…

学习unity官方的网络插件Netcode【一】

对bool值的个人理解&#xff1a; IsOwner&#xff1a;本地网络对象 IsLocalPlayer&#xff1a;本地网络玩家&#xff0c;&#xff08;本地网络玩家也是本地网络对象&#xff09; using Unity.Netcode; using UnityEngine; //个人理解&#xff1a;通过Rpc完成了一次客户端给服务…

【React Hooks原理 - createContext、useContext】

概述 在前面React Hooks系列介绍中我们知道React为了更好的处理不同生命周期的特殊处理&#xff0c;除了useContext这个Hooks之外的其他Hooks都拆为了Mount、Update两个阶段&#xff0c;而useContext内部并没有区分都是通过调用readContext来获取上下文的&#xff0c;下面就来…

微信小程序删除滑块 SwiperCell 自动收起 Van weapp van-swipe-cell 滑块自动收起 点击页面也自动收起滑块

在当前页面整个 view 中 给页面绑定 点击事件bindtap"onSwipeCellPage"给 van-swipe-cell 组件设置 id &#xff08;for循环可以添加 id"swip-cell-{{item.id}}" &#xff09;van-swipe-cell 组件 添加属性 当用户打开滑块时触发 bind:open"swiperCel…

Ajax原理-XMLHttpRequest、Promise以及封装简易的axios函数

这里写目录标题 一级目录二级目录三级目录 一、Ajax原理-XMLHttpRequest对象1.步骤 二、XMLHttpRequest-查询参数1.定义2.语法 二、XMLHttpRequest-数据提交1.需求2.核心 三、Promise1.定义2.好处3.三种状态 四、封装简易的axios1.需求&#xff1a;2.封装axios函数获取数据3.封…

使用UDP套接字编程详解【C语言】

UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09;是一种面向无连接的传输层协议&#xff0c;用于在计算机网络上发送数据。它与 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;相比具有轻量、高效的特点&…

英语(二)-我的学习方式

章节章节汇总我的学习方式历年真题作文&范文 目录 1、背单词 2、学语法 3、做真题 4、胶囊助学计划 写在最前&#xff1a;我是零基础&#xff0c;初二就听天书的那种。 本专栏持续更新学习资料 1、背单词 单词是基础&#xff0c;一定要背单词&#xff01;考纲要求要…

云动态摘要 2024-07-23

给您带来云厂商的最新动态,最新产品资讯和最新优惠更新。 最新优惠与活动 数据库上云优选 阿里云 2024-07-04 RDS、PolarDB、Redis、MongoDB 全系产品新用户低至首年6折起! [免费体验]智能助手ChatBI上线 腾讯云 2024-07-02 基于混元大模型打造,可通过对话方式生成可视化…

中文分词库 jieba 详细使用方法与案例演示

1 前言 jieba 是一个非常流行的中文分词库&#xff0c;具有高效、准确分词的效果。 它支持3种分词模式&#xff1a; 精确模式全模式搜索引擎模式 jieba0.42.1测试环境&#xff1a;python3.10.9 2 三种模式 2.1 精确模式 适应场景&#xff1a;文本分析。 功能&#xff1…

qt设置过滤器

1.创建事件过滤器类&#xff0c;在主窗口中安装事件过滤器 class PasteFilter : public QObject {Q_OBJECTpublic:PasteFilter(QObject *parent nullptr) : QObject(parent) {}protected:bool eventFilter(QObject *obj, QEvent *event) override {if (event->type() QEv…

【Zotero插件】Zotero Tag为文献设置阅读状态 win11下相关设置

【Zotero插件设置】Zotero Tag为文献设置阅读状态 win11下相关设置 1.安装Zotero Tag1.1安装1.2配置1.3 win11的相关设置1.3.1 字体安装 参考教程 2.支持排序的标注参考教程 1.安装Zotero Tag 1.1安装 Zotero Tag插件下载链接安装方法&#xff1a;Zotero–》工具–》附加组件…

googleTest 源码主线框架性分析——TDD 01

TDD&#xff0c;测试驱动开发&#xff0c;英文全称Test-Driven Development&#xff0c;简称TDD&#xff0c;是一种不同于传统软件开发流程的新型的开发方法。它要求在编写某个功能的代码之前先编写测试代码&#xff0c;然后只编写使测试通过的功能代码&#xff0c;通过测试来推…

苹果和乔布斯的传奇故事,从车库创业到万亿市值巨头

苹果公司的品牌故事&#xff0c;就像一部充满创新、挑战与辉煌的科幻大片&#xff0c;让人目不暇接。 故事始于1976年&#xff0c;那时&#xff0c;年轻的史蒂夫乔布斯与斯蒂夫沃兹尼亚克在加州的一个简陋车库里&#xff0c;用他们的热情和智慧&#xff0c;捣鼓出了世界上第一…

python学习之闭包与装饰器

一、闭包 闭包允许一个函数访问并操作函数外部的变量&#xff08;即父级作用域中的变量&#xff09;&#xff0c;即使在该函数外部执行。 特性&#xff1a; (1)外部函数嵌套内部函数。 (2)外部函数可以返回内部函数。 (3)内部函数可以访问外部函数的局部变量。 def out()…

《昇思 25 天学习打卡营第 18 天 | 扩散模型(Diffusion Models) 》

《昇思 25 天学习打卡营第 18 天 | 扩散模型&#xff08;Diffusion Models&#xff09; 》 活动地址&#xff1a;https://xihe.mindspore.cn/events/mindspore-training-camp 签名&#xff1a;Sam9029 扩散模型&#xff08;Diffusion Models&#xff09; 扩散模型概述 扩散模…