数据结构与算法之《二叉树》详解

news2024/11/15 16:39:34

标题:二叉树的思路及代码实现

作者:@Ggggggtm

寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景

文章目录

一、树的概念及结构

二、二叉树的概念及结构

2、1 二叉树的概念

2、2 二叉树的特点

2、3 二叉树的结构(图片)

2、4 特殊的二叉树

三、二叉树的代码及思路实现

3、1 二叉树的存储结构

3、1、1 二叉树的顺序存储结构

3、1、2 二叉树的链式存储结构

3、2 二叉树链式结构的实现

3、2、1 定义结构体

3、2、2 自定义一个二叉树

3、2、3 前序遍历

3、2、4 中序遍历

3、2、5 后序遍历

3、2、6 求树中节点的个数

3、2、7 求树中叶节点的个数

3、3 二叉树的性质


一、树的概念及结构

  二叉树是树的一种,所以在学习二叉树之前我们先了解一下树的概念及结构。

  树是一种 非线性 的数据结构,它是由 n n>=0 )个有限节点组成一个具有层次关系的集合。 把它 叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的
  • 有一个特殊的结点,称为根结点,根节点没有前驱结点;
  • 除根节点外,其余结点被分成M(M>0)个互不相交的集合T1T2……Tm,其中每一个集Ti(1<= i <= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以 0个或多个后继;
  • 因此,树是递归定义的。  

这里还有我们熟知的树中的一些概念:

  • 节点的度:一个节点含有的子树的个数称为该节点的度; 如上图:A的为6;
  • 叶节点或终端节点:度为 0 的节点称为叶节点; 如上图: B C H I... 等节点为叶节点;
  • 非终端节点或分支节点:度不为 0 的节点; 如上图: D E F G... 等节点为分支节点;
  • 双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图: A B 的父节点;
  • 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图: B A 的孩子节点
  • 兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图: B C 是兄弟节点;
  • 树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为 6;
  • 节点的层次:从根开始定义起,根为第 1 层,根的子节点为第 2 层,以此类推;
  • 树的高度或深度:树中节点的最大层次; 如上图:树的高度为 4;
  • 节点的祖先:从根到该节点所经分支上的所有节点;如上图: A 是所有节点的祖先;
  • 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是 A 的子孙;
  • 森林:由 m m>0 )棵互不相交的多颗树的集合称为森林;(数据结构中的学习并查集本质就是 一个森林);

  在这里我们要注意树与非树的区别是;

  • 子树是不相交的;
  • 除了根结点外,每个节点有且仅有一个父结点;
  • 一颗N个结点的树有N-1条边。

以下我给大家举几个树和非树的例子,可以先简单了解以下。

树:

非树:

二、二叉树的概念及结构

2、1 二叉树的概念

  一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子树和右子树的二叉树组成。

2、2 二叉树的特点

  • 每个结点最多有两棵子树,即二叉树不存在度大于2的结点。
  • 二叉树的子树有左右之分,其子树的次序不能颠倒。

2、3 二叉树的结构(图片)

2、4 特殊的二叉树

  1. 满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉 树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。
  2. 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对 于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号 从1n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。

三、二叉树的代码及思路实现

3、1 二叉树的存储结构

   二叉树一般可以使用两种结构存储,一种顺序结构,一种链式结构

3、1、1 二叉树的顺序存储结构

  顺序结构存储就是使用 数组来存储 ,一般使用数组 只适合表示完全二叉树 ,因为不是完全二叉树 会有空间的浪费。而现实中使用中只有堆才会使用数组来存储。二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。

3、1、2 二叉树的链式存储结构

  二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成数据域左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。链式结构又分为二叉链和三叉链,当前我们学习中一般都是二叉链。

3、2 二叉树链式结构的实现

  二叉树的链式结构实现都有哪些模块呢?接下来我简单的给大家总结一下:

  1. 定义结构体;
  2. 自定义一个二叉树;
  3. 前序遍历;
  4. 中序遍历;
  5. 后序遍历;
  6. 求树中节点的个数;
  7. 求叶节点的个数。

接下来我们来看一下各个模块实现的细节以及详解。

3、2、1 定义结构体

   定义结构体时,由上面的链式存储结构我们直到该结构体应该包含一个存储数据的变量,和指向左右分支节点的指针;我们看代码实现。

typedef char BTDataType;
typedef struct BinaryTreeNode
{
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
	BTDataType data;
}BTNode;

3、2、2 自定义一个二叉树

  首先我们自己要有一个二叉树,简单的二叉树即可。因为下面的操作都是在二叉树上进行的。这里给出一个简单的二叉树,如下图及代码实现:

	BTNode* A = (BTNode*)malloc(sizeof(BTNode));
	A->data = 'A';
	A->left = NULL;
	A->right = NULL;

	BTNode* B = (BTNode*)malloc(sizeof(BTNode));
	B->data = 'B';
	B->left = NULL;
	B->right = NULL;

	BTNode* C = (BTNode*)malloc(sizeof(BTNode));
	C->data = 'C';
	C->left = NULL;
	C->right = NULL;

	BTNode* D = (BTNode*)malloc(sizeof(BTNode));
	D->data = 'D';
	D->left = NULL;
	D->right = NULL;

	BTNode* E = (BTNode*)malloc(sizeof(BTNode));
	E->data = 'E';
	E->left = NULL;
	E->right = NULL;
	
	A->left = B;
	A->right = C;
	B->left = D;
	B->right = E;

3、2、3 前序遍历

  什么是前序遍历呢?我们先来看一下比较官方的解释。

  NLR :前序遍历(Preorder Traversal 亦称先序遍历 )—— 访问根结点的操作发生在遍历其左右子树之前。

   我在稍微解释一下前序遍历的概念:其实就是遍历树时,先访问根,再访问左子树,最后访问右子树。这里要注意的是,当我们访问到左子树时,我们把左子树当成一个新树,同时也应该满足先访问根,在访问左子树,最后访问右子树。我们发现前序遍历先访问了整个树的跟后,再把整个树左子树访问完后,再从下往上依次访问整个数的右子树。

   其实我们不难发现,当一个子树的节点为空时,我们就不再往下访问了,开始从下往上访问右子树。这好像与递归有点类似哦!其实就是用递归实现的遍历。我们结合着下图理解一下:

 注:

  • 往下的箭头表示递归调用;
  • 往上的箭头表示返回,也就是归。

下面我们看代码的实现。

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

3、2、4 中序遍历

  什么是中序遍历呢?同样,我们先来看一下比较官方的解释。

   LNR:中序遍历 (Inorder Traversal)—— 访问根结点的操作发生在遍历其左右子树的中 间。
  通俗来讲,其实就是遍历树时, 先访问左子树,再访问根,最后访问右子树。对比前序遍历,中序遍历与前序遍历大同小异,只不过是访问顺序发生了变化。我们结合这下图理解一下:

 注:

  • 往下的箭头表示递归调用;
  • 往上的箭头表示返回,也就是归。

下面我们看代码的实现。

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

3、2、5 后序遍历

  当我们了解完前序遍历和中序遍历后,我们理解后序遍历接很简单了。 我们先看比较官方的解释。

  LRN :后序遍历 (Postorder Traversal)—— 访问根结点的操作发生在遍历其左右子树之后。
  通俗来讲,其实就是遍历树时, 先访问左子树,再右子树,最后访问根。我们直接看图:
注:
  • 往下的箭头表示递归调用;
  • 往上的箭头表示返回,也就是归。

下面我们看代码的实现。

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

3、2、6 求树中节点的个数

  我们在统计树中节点的个数时,需要遍历整个树才行。当然,遍历整个树也是需要用递归的。当我们遇到某个节点为空时,我们就返回0,不是空时我们就返回1。我们结合着代码一起理解一下。 

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

3、2、7 求树中叶节点的个数

  我们知道,叶节点的度为0,也就是叶节点的左子树和右子树均为空。同样,我们使用递归遍历整个树,遇到节点为空时返回零,遇到节点的左子树和右子树均为空返回1。我们看代码的实现。 

int TreeLeafSize(BTNode* root)
{
	if (root == 0)
		return 0;

	if (root->left == NULL && root->right == NULL)
		return 1;

	return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}

3、3 二叉树的性质

  通过上面对二叉树的理解,我给大家总结出了二叉树的一些性质:

  1. 若规定根节点的层数为 1 ,则一棵非空二叉树的 i 层上最多有 2^(i-1) 个结点;
  2. 若规定根节点的层数为 1 ,则 深度为 h 的二叉树的最大结点数是 2^h- 1;
  3. 对任何一棵二叉树 , 如果度为 0 其叶结点个数为 n0, 度为 2 的分支结点个数为 n2, 则有 n0 n2 1;
  4. 若规定根节点的层数为 1 ,具有 n 个结点的满二叉树的深度 h=LogN。

  通过上面的学习,我们可以对二叉树有一个新的认识和理解,希望本编文章对您有所帮助,感谢阅读ovo! 

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

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

相关文章

机器学习之单变量线性回归

1、线性回归基础概念&#xff1a; 回归模型&#xff1a;regression model数据集&#xff1a;包含feature&#xff08;输入变量&#xff09;和与之对应的target&#xff08;输出变量&#xff09;训练集&#xff1a;training set输入数据&#xff1a;x&#xff08;feature or in…

玩转redis(二)——redis持久化

文章目录前言一、RDB1.save 和 bgsave对比2.RDB的优点和缺点2.1 优点2.2 缺点二、AOF1.AOF重写2.AOF的优点和缺点2.1 优点2.2 缺点3 RDB和AOF对比三、AOFRDB混合持久化1 原理2 如图Redis数据备份策略&#xff08;其实就是去备份我们的rdb/aof两个文件&#xff09;&#xff1a;四…

LeetCode刷题复盘笔记—一文搞懂完全背包之139. 单词拆分问题(动态规划系列第十六篇)

今日主要总结一下动态规划完全背包的一道题目&#xff0c;139. 单词拆分 题目&#xff1a;139. 单词拆分 Leetcode题目地址 题目描述&#xff1a; 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 注意&#xff1a;…

(附源码)SSM失物招领平台 毕业设计 271621

SSM失物招领平台的设计与实现 摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对失物招领等问…

红队隧道应用篇之MsfPortfwd端口转发(三)

简介 Meterpreter shell中的portfwd命令最常用作透视技术&#xff0c;允许直接访问攻击系统无法访问的机器, 例如不出网的内网主机, 前提是你要有一个此内网网段的能出网的主机的Meterpreter shell 命令参数 add: 增加端口转发 delete: 删除指定的端口转发 list: 查看端口转…

Spring Cloud Alibaba Nacos 安装

1.Nacos 官网下载地址 Releases alibaba/nacos GitHub 2.使用 rz 命令上传到 虚拟机上 3.解压 tar -zxvf nacos-server-2.1.2.tar.gz 注&#xff1a;解压后&#xff0c;可以直接启动&#xff0c;访问地址&#xff1a;http://192.168.10.121:8848/nacos/ 用户名:nacos 密码:n…

JavaEE进阶:Bean 作⽤域和⽣命周期

文章目录一、Bean 的作用域问题1、案例2、分析二、作用域定义1、Bean 的 6 种作用域① singleton② prototype③ request④ session⑤ application⑥ websocket⑦ 单例作用域(singleton)和全局作用域(application)区别2、设置作用域3、案例修改三、Bean 原理分析1、Bean 执行流…

学生花卉网网页设计作品 学生鲜花网页模板 简单在线花店主页成品 鲜花网页制作 HTML学生花店商城网站作业设计

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

vue3 创建项目、安装依赖、启动项目

1. 搭建vue开发环境 下载安装最新版node.js https://blog.csdn.net/weixin_41192489/article/details/117979077 2. 执行项目创建命令 打开命令行工具 cnpm init vuelatest无 cnpm 的朋友先执行 npm i cnpm 遇到这种提示时&#xff0c;输入 y 回车 3. 选择项目创建配置 参考下…

安卓玩机搞机技巧综合资源-----关闭miui广告 怎么省电 替换开机动画 LOGO 锁屏 壁纸等等【五】

接上篇 安卓玩机搞机技巧综合资源------如何提取手机分区 小米机型代码分享等等 【一】 安卓玩机搞机技巧综合资源------开机英文提示解决dm-verity corruption your device is corrupt. 设备内部报错 AB分区等等【二】 安卓玩机搞机技巧综合资源------EROFS分区格式 小米红…

Windows OpenGL ES 图像白平衡色温

目录 一.OpenGL ES 图像白平衡色温 1.原始图片2.效果演示 二.OpenGL ES 图像白平衡色温源码下载三.猜你喜欢 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 基础 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 特效 零…

Sentinel规则持久化

Sentinel规则持久化 根据之前遇到的问题可以看出&#xff0c;当服务关闭后Sentinel就不会再有对应的信息&#xff0c;也就是临时保存的&#xff0c;下面就是要进行持久化的保存 将限流配置规则持久化进Nacos保存&#xff0c;只要刷新8401某个rest地址&#xff0c;sentinel控制台…

解决安装 CentOS 8 错误: Error setting up base repository

1. 问题 安装 CentOS-8 常常会遇到这样的问题&#xff0c;即在安装过程中会发现软件源的设置&#xff0c;无论怎样都会显示这样的错误 “Error setting up base repository”。 导致这一问题的原因是&#xff0c;由于 CentOS-8 的生命周期较短&#xff0c;其基本的软件库已早…

数字化成汽车零部件发展趋势,数商云SRM系统库存管理模块助力企业转型升级

近年来&#xff0c;随着人工智能、物联网等技术应用边界不断拓展&#xff0c;数字化转型逐渐成为企业发展的趋势。零部件是汽车产业发展最为重要的基础&#xff0c;汽车零部件制造作为突破的重点领域之一&#xff0c;引领汽车零部件行业发展可加快提升汽车产业核心竞争力&#…

2022-03-18-SpringBoot

layout: post #标题配置 title: SpringBoot #时间配置 date: 2022-03-18 18:54:00 0800 #目录配置 categories: 框架 #标签配置 tag: 学习笔记 content {:toc} 一.SpringBoot基础 1-今日内容 Spring概述、快速入门SpringBoot配置SpringBoot整合 2-SpringBoot概述 SpringB…

【Cycle-Interactive GAN:弱光图像增强】

Cycle-Interactive Generative Adversarial Network for Robust Unsupervised Low-Light Enhancement &#xff08;基于循环交互式生成式对抗网络的鲁棒无监督弱光增强&#xff09; 近年来的无监督弱光增强方法摆脱了对成对训练数据拟合的基本限制&#xff0c;在调节图像亮度…

今年大促季,阿里云容器服务有哪些技术和应用新突破?

联合作者&#xff1a;志敏&#xff0c;冬岛&#xff0c;戒空&#xff0c;邓隽&#xff0c;佳旭&#xff0c;谢乘胜&#xff0c;元毅&#xff0c;溪洋在 2022 年的双 11 大促季中&#xff0c;阿里云容器服务&#xff08;简称 ACK&#xff09;、容器镜像服务&#xff08;简称 ACR…

教你如何基于Redis来实现高性能延时消息队列!

最近在倒腾自建博客后端系统&#xff0c;需要用到延时任务的功能&#xff0c;但手头只有一套MySQL和Redis&#xff0c;如果搞一套MQ成本有点大&#xff0c;于是想着用redis实现延时消息队列。有些场景用数据库的定时扫表也能简单实现延时消息的功能&#xff0c;不过对于我这边的…

Frida-Dexdump 脱壳工具下载使用以及相关技术介绍

Frida-Dexdump 脱壳工具下载使用以及相关技术介绍 文章目录Frida-Dexdump 脱壳工具下载使用以及相关技术介绍前言一、查壳、反编译、APK工具推荐二、查壳1.方式12.方式二三、脱壳1.启动frida服务2.方式一3.方式二四、反编译总结前言 本案例使用的App是&#xff1a;引力播.apk&…

多无人机空中机器人施工任务分配(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 空中机器人作为近年来新兴的热点得到了广泛的关注。小型空中机器人在没有外界卫星定位信号的前提下的导航是空中机器人的研究内…