深入理解数据结构第三弹——二叉树(3)——二叉树的基本结构与操作

二叉树(1):深入理解数据结构第一弹——二叉树(1)——堆-CSDN博客

二叉树(2):深入理解数据结构第二弹——二叉树(2)——堆排序及其时间复杂度-CSDN博客

前言:

在前面我们讲了堆及其应用,帮助我们初步了解了二叉树的一些原理,但那与真正的二叉树仍有不同,今天我们就来正式学习一下二叉树的基本结构及其基本操作

目录

一、什么是二叉树?

二、二叉树的节点结构

三、二叉树的遍历

前序遍历:

中序遍历:

后序遍历:

四、二叉树的基本操作

1、创建二叉树

2、前序、中序、后序

3、求二叉树的节点个数

4、求二叉树叶子节点的个数

5、树的高度

6、二叉树第k层的节点个数

7、二叉树查找值为x的节点

五、完整代码实例

总结


一、什么是二叉树?

在前面的文章中我们已经提到过二叉树的结构及其特点,这里我们不过多赘述,有不理解的可以点文章开头的链接去前面看一下

二、二叉树的节点结构

二叉树有左右子树之分,且二叉树与我们所学的其他数据结构不同的点在于,之前我们所学的都是各类插入或者删除等等,但是二叉树需要做的操作是运用递归遍历,所以二叉树的节点结构与之前几个有很大不同

typedef int TreeDataType;
typedef struct Tree
{TreeDataType a;struct Tree* left;struct Tree* right;
}Tree;

节点结构里面定义有两个递归,是为了方便后面的遍历

三、二叉树的遍历

二叉树的遍历是我们学习二叉树首先要了解的东西,我们都知道二叉树其实就是一串数组,那我们是如何访问他们的呢?这里就牵扯到了遍历顺序的问题。

二叉树的遍历有三种形式:前序、中序和后序

  1. 前序遍历:

    • 特点:按照“根-左-右”的顺序遍历二叉树。
    • 特点:首先访问根节点,然后递归地前序遍历左子树,最后递归地前序遍历右子树。
    • 应用:常用于复制一棵树、计算表达式的值等。
  2. 中序遍历:

    • 特点:按照“左-根-右”的顺序遍历二叉树。
    • 特点:先递归地中序遍历左子树,然后访问根节点,最后递归地中序遍历右子树。
    • 应用:常用于二叉搜索树,可以得到一个递增的有序序列。
  3. 后序遍历:

    • 特点:按照“左-右-根”的顺序遍历二叉树。
    • 特点:先递归地后序遍历左子树,然后递归地后序遍历右子树,最后访问根节点。
    • 应用:常用于释放二叉树的内存空间,或者计算表达式的值。

    例如:

四、二叉树的基本操作

我先把主函数给出,接下来就将按照主函数中的这些功能一步一步来实现

int main()
{Tree* root = CreatTree();//前序printf("前序:");PrevTree(root);printf("\n");//中序printf("中序:");HalfTree(root);printf("\n");//后序printf("后序:");PostTree(root);printf("\n");//节点个数int count = BTreeSize(root);printf("BTreeSize:%d\n", count);//叶子节点个数printf("BTreeLeafSize:%d\n", BTreeLeafSize(root));//树的高度printf("BTreeHigh:%d\n", BTreeHigh(root));//二叉树第k层节点个数printf("BTreeLevelKSize:%d\n", BTreeLevelKSize(root, 3));//二叉树查找值为x的节点return 0;
}

1、创建二叉树

//二叉树
typedef int TreeDataType;
typedef struct Tree
{TreeDataType a;struct Tree* left;struct Tree* right;
}Tree;
//初始化二叉树
Tree* TreeInit(TreeDataType x)
{Tree* m = (Tree*)malloc(sizeof(Tree));if (m == NULL){perror("TreeInit");return NULL;}m->a = x;m->left = NULL;m->right = NULL;return m;
}
//创建一个二叉树
Tree* CreatTree()
{Tree* n1 = TreeInit(3);Tree* n2 = TreeInit(5);Tree* n3 = TreeInit(6);Tree* n4 = TreeInit(7);Tree* n5 = TreeInit(9);n1->left = n2;n1->right = n3;n2->left = n4;n2->right = n5;return n1;
}

2、前序、中序、后序

前序、中序和后序其实就是数据按照上面图片中的形式进行遍历

//前序
void PrevTree(Tree* root)
{if (root == NULL){printf("N ");return;}printf("%d ", root->a);PrevTree(root->left);PrevTree(root->right);
}
//中序
void HalfTree(Tree* root)
{if (root == NULL){printf("N ");return;}HalfTree(root->left);printf("%d ", root->a);HalfTree(root->right);
}
//后序
void PostTree(Tree* root)
{if (root == NULL){printf("N ");return;}PostTree(root->left);PostTree(root->right);printf("%d ", root->a);
}

运行结果:

3、求二叉树的节点个数

//二叉树节点个数
int BTreeSize(Tree* root)
{//分治的思想if (root == NULL){return 0;}return BTreeSize(root->left) + BTreeSize(root->right)+1 ;
}

用到了递归的思想,下面的内容都要用递归来解决,如果递归学的不太好建议画图来看这些过程如何进行的

运行结果:

4、求二叉树叶子节点的个数

//二叉树叶子节点个数
int BTreeLeafSize(Tree* root)
{if (root == NULL){return 0;}if (root->left == NULL && root->right == NULL){return 1;}return BTreeLeafSize(root->left) + BTreeLeafSize(root->right);
}

运行结果:

5、树的高度

//求二叉树高度
int BTreeHigh(Tree* root)
{if (root == NULL){return 0;}int leftHigh = BTreeHigh(root->left);int rightHigh = BTreeHigh(root->right);return leftHigh > rightHigh ? leftHigh + 1 : rightHigh + 1;
}

运行结果:

6、二叉树第k层的节点个数

//二叉树第k层节点个数
int BTreeLevelKSize(Tree* root, int k)
{assert(k > 0);if (root == NULL){return 0;}if (k == 1){return 1;}return BTreeLevelKSize(root->left, k - 1) + BTreeLevelKSize(root->right, k - 1);
}

运行结果:

7、二叉树查找值为x的节点

//二叉树查找值为x的节点
Tree* BTreeFind(Tree* root,int x)
{if (root == NULL)return NULL;if (root->a == x)return root;Tree* ret1 = BTreeFind(root->left, x);if (ret1){return ret1;}Tree* ret2 = BTreeFind(root->right, x);if (ret2){return ret2;}
}

五、完整代码实例

//二叉树
typedef int TreeDataType;
typedef struct Tree
{TreeDataType a;struct Tree* left;struct Tree* right;
}Tree;
//初始化二叉树
Tree* TreeInit(TreeDataType x)
{Tree* m = (Tree*)malloc(sizeof(Tree));if (m == NULL){perror("TreeInit");return NULL;}m->a = x;m->left = NULL;m->right = NULL;return m;
}
//创建一个二叉树
Tree* CreatTree()
{Tree* n1 = TreeInit(3);Tree* n2 = TreeInit(5);Tree* n3 = TreeInit(6);Tree* n4 = TreeInit(7);Tree* n5 = TreeInit(9);n1->left = n2;n1->right = n3;n2->left = n4;n2->right = n5;return n1;
}
//前序
void PrevTree(Tree* root)
{if (root == NULL){printf("N ");return;}printf("%d ", root->a);PrevTree(root->left);PrevTree(root->right);
}
//中序
void HalfTree(Tree* root)
{if (root == NULL){printf("N ");return;}HalfTree(root->left);printf("%d ", root->a);HalfTree(root->right);
}
//后序
void PostTree(Tree* root)
{if (root == NULL){printf("N ");return;}PostTree(root->left);PostTree(root->right);printf("%d ", root->a);
}
//二叉树节点个数
int BTreeSize(Tree* root)
{//分治的思想if (root == NULL){return 0;}return BTreeSize(root->left) + BTreeSize(root->right)+1 ;
}
//二叉树叶子节点个数
int BTreeLeafSize(Tree* root)
{if (root == NULL){return 0;}if (root->left == NULL && root->right == NULL){return 1;}return BTreeLeafSize(root->left) + BTreeLeafSize(root->right);
}
//求二叉树高度
int BTreeHigh(Tree* root)
{if (root == NULL){return 0;}int leftHigh = BTreeHigh(root->left);int rightHigh = BTreeHigh(root->right);return leftHigh > rightHigh ? leftHigh + 1 : rightHigh + 1;
}
//二叉树第k层节点个数
int BTreeLevelKSize(Tree* root, int k)
{assert(k > 0);if (root == NULL){return 0;}if (k == 1){return 1;}return BTreeLevelKSize(root->left, k - 1) + BTreeLevelKSize(root->right, k - 1);
}
//二叉树查找值为x的节点
Tree* BTreeFind(Tree* root,int x)
{if (root == NULL)return NULL;if (root->a == x)return root;Tree* ret1 = BTreeFind(root->left, x);if (ret1){return ret1;}Tree* ret2 = BTreeFind(root->right, x);if (ret2){return ret2;}
}
int main()
{Tree* root = CreatTree();//前序printf("前序:");PrevTree(root);printf("\n");//中序printf("中序:");HalfTree(root);printf("\n");//后序printf("后序:");PostTree(root);printf("\n");//节点个数int count = BTreeSize(root);printf("BTreeSize:%d\n", count);//叶子节点个数printf("BTreeLeafSize:%d\n", BTreeLeafSize(root));//树的高度printf("BTreeHigh:%d\n", BTreeHigh(root));//二叉树第k层节点个数printf("BTreeLevelKSize:%d\n", BTreeLevelKSize(root, 3));//二叉树查找值为x的节点return 0;
}

运行结果:

总结

总而言之,二叉树其实是对我们运用递归来遍历数据的考察,由于篇幅原因,这里我们只对二叉树的结构进行了大致的讲解,有不理解的地方欢迎与我私信或者在评论区中指出

创作不易,还请各位大佬点个小小的赞!!!

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

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

相关文章

面试:HashMap

目录 1、底层数据结构,1.7 与1.8有何不同? 2、为何要用红黑树,为何一上来不树化,树化阈值为何是8,何时会树化,何时会退化为链表? 3、索引如何计算? hashCode都有了,为何还要提供hash()方法?数组容量为…

【Easy云盘 | 第十二篇】分享模块(获取分享信息、校验分享码、获取文件列表)

文章目录 4.4.4获取分享信息4.4.5校验分享码4.4.6获取文件列表 4.4.4获取分享信息 明天做 4.4.5校验分享码 明天做 4.4.6获取文件列表 明天做

Vue3大事件项目1 登录注册

创建项目 引入 element-ui 组件库 登录:注册样式准备之后,配置校验规则(4个条件:一数据、二规则) 1. 校验相关 (1) 给当前表单绑上整个的数据对象:el-form > :model"ruleForm" 绑…

云服务器是不是云盘?

​  云服务器是不是云盘?云服务器和云盘是两个不同的概念,尽管它们都是云计算服务的一部分。云服务器是一种提供计算能力的服务,可以运行各种应用程序和服务,而云盘则是一种提供数据存储和共享服务的工具。 具体来说: 云服务器…

【Qt】事件

目录 一、介绍 二、进入离开事件 三、鼠标事件 3.1 鼠标单击事件 3.2 鼠标释放事件 3.3 鼠标双击事件 3.4 鼠标移动事件 3.5 滚轮事件 四、按键事件 4.1 单个按键 4.2 组合按键 五、定时器 5.1 QTimerEvent类 5.2 QTimer类 5.3 获取系统日期及时间 六、窗口移…

插值表达式

<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title>插值表达式</title> </head> &l…

两个有序的链表合并成一个【C语言】

比如&#xff1a; 输入&#xff1a;1->2->4, 1->3->4 输出&#xff1a;1->1->2->3->4->4 #include <stdio.h> #include <stdlib.h>typedef struct Node {int data;struct Node* next; } Node, *LinkedList;// 创建一个新节点 Node* cr…

理解七层网络协议

osi体系结构 上三路&#xff08;管数据&#xff09; 应用层 通过http等&#xff0c;把传输的格式&#xff0c;数据打包 处理网络应用。直接为端用户服务&#xff0c;提供各类应用过程的接口和用户接口。例如&#xff1a;HTTP、Tenlent、FTP、SMTP、NFS等。基于TCP的FTP、HTTP…

mySql数据库学习001-创建数据表及表数据的增删改操作

创建数据表及表数据的增删改操作 一、创建数据库 create table if not exists user(id int unsigned primary key auto_increment,username varchar(20),gender enum(男,女,保密) default 保密 )解释&#xff1a; if not exists 表示数据表不存在就创建&#xff1b;unsigned…

蓝桥杯刷题 前缀和与差分-[NewOJ P1819]推箱子(C++)

题目描述 在一个高度为H的箱子前方&#xff0c;有一个长和高为N的障碍物。 障碍物的每一列存在一个连续的缺口&#xff0c;第i列的缺口从第l各单位到第h个单位&#xff08;从底部由0开始数&#xff09;。 现在请你清理出一条高度为H的通道&#xff0c;使得箱子可以直接推出去。…

深度学习理论基础(二)深度神经网络DNN

目录 一、基础知识点Ⅰ 参数部分Ⅱ 模型部分 二、深度神经网络模型搭建1. 准备数据集2. 划分数据集3. 搭建模型4. 训练网络5. 测试网络6. 保存与导入模型 神经网络通过学习大量样本的输入与输出特征之间的关系&#xff0c;以拟合出输入与输出之间的方程&#xff0c;学习完成后&…

Qt Creator 设置 One Dark Pro主题

这个是我基于上网很多教程设置 C 美化加一些基本的配置&#xff0c;下载这个导入一键设置&#xff0c;省去很多烦恼&#xff01;&#xff01;&#xff01; Qt Creator 13.0.0 (Community) 新版的 Qt 编辑器还需要一个文件&#xff0c;不然主界面黑屏&#xff0c;网上很多教程都…

window系统实现不同版本的python(Anaconda)

1.创建不同的环境 https://blog.csdn.net/wz947324/article/details/80228679&#xff1b; https://blog.csdn.net/miracleoa/article/details/106115730&#xff1b; 2.cuda不用版本安装 https://www.bilibili.com/video/BV1nL4y1b7oT/?spm_id_from333.337.search-card.al…

每日一题(leetcode31):下一个排列-思维

思路&#xff1a;从后往前找到第一个nums[i-1]>nums[i] 然后从后往前(len-1 -->i(包含))找到第一个大于nums[i-1]的数&#xff0c;与nums[i-1]交换&#xff0c;然后对下标区间为[i,len-1]的元素进行排序。 class Solution { public:void nextPermutation(vector<in…

[深度学习] 无人车环境准备

1. 安装过程基本遵循以下步骤 电脑端环境配置 - OriginBot智能机器人开源套件 需要注意以下两点&#xff1a; 1> 由于深度学习需要的包和镜像体积都比较大&#xff0c;所以虚拟机硬盘大小建议120GB 2> 虚拟机的网络适配器应该设置为桥接模式&#xff0c;如果使用NAT模…

im-system 第十一章

在线状态功能 需求 需求一&#xff1a;需要实时的更新好友的状态&#xff0c;有一个标识可以辨别在线和离线&#xff0c;在线和离线可以实时得到感知&#xff0c;手动修改忙碌啥的状态可以实时通知到好友 需求二&#xff1a;打开群组等&#xff0c;可以获取到这一批人的在线…

vivado 使用网表插入调试探测流程

使用网表插入调试探测流程 在 Vivado 工具中插入调试核的过程以分层方式来演示 &#xff0c; 以应对多样化的 Vivado 用户组的不同需求 &#xff1a; • 最高层是根据选定调试的一组信号线来自动创建并配置 Integrated Logic Analyzer (ILA) 核的简单向导。 • 下一层是“…

File,IO流,递归详解

File类 介绍 java.io.File类是Java语言提供了用来描述文件和目录(文件夹)的 构造 方法 注意&#xff1a; 构造方法中通常用的是第一个方法文件和目录可以通过File封装成对象File封装的对象仅仅是一个路径名&#xff0c;它是可以存在的&#xff0c;也可以不存在 绝对路径…

【二分查找】Leetcode x 的平方根

题目解析 69. x 的平方根 这道题表面是没有顺序性&#xff0c;但是我们可以发现如果使用枚举策略&#xff0c;它是包含顺序性质的&#xff0c;因此我们将枚举算法改进成二分算法 算法讲解 我们让left指针指向1&#xff0c; right指针指向x 如果当前的mid计算出来的平方 &g…

什么是商家转账到零钱

商家转账到零钱是什么&#xff1f; 通过商家转账到零钱这个功能&#xff0c;如果我们系统需要对用户支付费用&#xff0c;比如发放佣金、提成、退款之类的&#xff0c;可以直接转账到用户的微信零钱。 【商家转账到零钱】是【企业付款到零钱】的升级版&#xff0c;2022年5月1…