深入理解数据结构第三弹——二叉树(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.rhkb.cn/news/300411.html

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

相关文章

如何通过ArkTS卡片的Canvas自定义绘制能力实现五子棋游戏卡片

介绍 本示例展示了如何通过ArkTS卡片的Canvas自定义绘制能力实现一个简单的五子棋游戏卡片。 使用Canvas绘制棋盘和黑白棋子的落子。通过卡片支持的点击事件进行交互,让用户在棋盘上进行黑白棋子的对局。通过TS的逻辑代码实现五子棋输赢判定、回退等逻辑计算&…

多线程学习-线程安全

目录 1.多线程可能会造成的安全问题 2. static共享变量 3.同步代码块 4.同步方法 5.使用Lock手动加锁和解锁 6.死锁 1.多线程可能会造成的安全问题 场景:三个窗口同时售卖100张电影票,使用线程模拟。 public class MyThread extends Thread{//tic…

时序分解 | Matlab实现GSWOA-VMD改进鲸鱼优化算法优化变分模态分解时间序列信号分解

时序分解 | Matlab实现GWO-CEEMDAN基于灰狼算法优化CEEMDAN时间序列信号分解 目录 时序分解 | Matlab实现GWO-CEEMDAN基于灰狼算法优化CEEMDAN时间序列信号分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现GSWOA-VMD改进鲸鱼优化算法优化变分模态分解时间序…

GitHub入门与实践

ISBN: 978-7-115-39409-5 作者:【日】大塚弘记 译者:支鹏浩、刘斌 页数:255页 阅读时间:2023-08-05 推荐指数:★★★★★ 好久之前读完的了,一直没有写笔记。 这本入门Git的书籍还是非常推荐的,…

前端实现token的无感刷新#记录

因为服务器的token一版不会设置太长,token过期后就需要重新登录,频繁的登录会造成体验不好的问题,因此,需要体验好的话,就需要定时去刷新token,并替换之前的token。以下是token失效的效果: 那么…

Vue3组件基础示例

组件是vue中最推崇的,也是最强大的功能之一,就是为了提高重用性,减少重复性的开发。 如何使用原生HTML方法实现组件化 在使用原生HTML开发时,我们也会遇到一些常见的功能、模块,那么如何在原生HTML中使用组件化呢&am…

动态规划——线性dp

图片来源&#xff1a;_snowstorm_ 路线问题的状态表示一般都可以用点的坐标来表示 状态表示数组维数的确定原则&#xff1a;在可以用该维数表示出答案的基础上维数尽可能最小 数字三角形 acwing 898 #include<iostream> #include<cstring> #include<algorith…

python学习笔记——控制流

目录 1. 控制流**** 1.1. if-elif-else语句**** 1.2. 循环结构**** 1.2.1. for循环**** 1.2.2. While循环**** 1.2.3. 嵌套循环**** 1.2.4. 循环的控制**** 1.2.4.1. Break**** 1.2.4.2. Continue**** 1.2.5. 遍历**** 1.2.5.1. dict**** 1.2.5.1.1. 遍历key&#x…

三分钟带你了解,可重构柔性装配生产线

产品个性化时代&#xff0c;产品小批量、多批次&#xff0c;行业常用高柔性的人-机混合装配线实现跨品类产品装配&#xff0c;但产品的装配质量一致性差、效率低成为行业痛点。富唯智能联合清华大学提出了可重构柔性装配方法和技术&#xff0c;实现跨品类产品的数控自动化装配。…

京东云轻量云主机8核16G配置租用价格1198元1年、4688元三年

京东云轻量云主机8核16G服务器租用优惠价格1198元1年、4688元三年&#xff0c;配置为8C16G-270G SSD系统盘-5M带宽-500G月流量&#xff0c;华北-北京地域。京东云8核16G服务器活动页面 yunfuwuqiba.com/go/jd 活动链接打开如下图&#xff1a; 京东云8核16G服务器优惠价格 京东云…

原型变量、原子操作、原子性、内存序

一、原子变量、原子操作 锁竞争&#xff1a;互斥锁、条件变量、原子变量、信号量、读写锁、自旋锁。在高性能基础组件优化的时候&#xff0c;为了进一步提高并发性能&#xff0c;可以使用原子变量。性能&#xff1a;原子变量 > 自旋锁 > 互斥锁。 操作临界资源的时间较长…

7 个 iMessage 恢复应用程序/软件可轻松恢复文本

由于误操作、iOS 升级中断、越狱失败、设备损坏等原因&#xff0c;您可能会丢失 iPhone/iPad 上的 iMessages。意外删除很大程度上增加了这种可能性。更糟糕的是&#xff0c;这种情况经常发生在 iDevice 缺乏备份的情况下。 &#xff08;iPhone消息消失还占用空间&#xff1f;&…

如何利用HubSpot 出海CRM实现精准海外客户定位与拓展?

在当今全球化的商业环境中&#xff0c;企业寻求海外市场的拓展已成为增长的重要策略。然而&#xff0c;海外市场的复杂性和多样性为企业带来了巨大的挑战。为了有效地定位和拓展海外客户&#xff0c;许多企业选择了HubSpot 出海CRM作为他们的营销和销售管理工具。今天运营坛将带…

Web题记

反序列化补充知识&#xff1a; private变量会被序列化为&#xff1a;\x00类名\x00变量名 protected变量会被序列化为: \x00\*\x00变量名 public变量会被序列化为&#xff1a;变量名web254 这个逻辑不难&#xff0c;自己刚看的时候还奇怪是不是自己哪里想错了&#xff0c;因为…

java云his系统源码 B/S版+saas智慧医院云his系统源码 二甲医院应用多年 运行稳定

java云his系统源码 B/S版saas智慧医院云his系统源码 二甲医院应用多年 运行稳定 医院云HIS系统简介&#xff1a; SaaS模式Java版云HIS系统&#xff0c;在公立二甲医院应用三年&#xff0c;经过多年持续优化和打磨&#xff0c;系统运行稳定、功能齐全&#xff0c;界面布局合理…

mac电脑安装redis教程

1、下载地址 Download | RedisRedisYou can download the last Redis source files here. For additional options, see the Redis downloads section below.Stable (7.2)Redis 7.2 …https://redis.io/download/#redis-downloads 2、安装 2.1 解压下载后的压缩文件 2.2 进入…

【C++】类和对象(中篇)

目录 1、类中的6个默认成员函数 2、构造函数 2.1 概念 2.2 特性 3、析构函数 3.1 概念 3.2 特性 4、拷贝构造函数 4.1 概念 4.2 特征 5、赋值运算符重载 5.1 运算符重载 5.1.1 全局的operator ​编辑 5.1.2 成员函数的operator 5.2 赋值运算符重载 6、创建Date类…

ffmpeg 将多个视频片段合成一个视频

ffmpeg 将多个视频片段合成一个视频 References 网络视频 6 分钟的诅咒。 新建文本文件 filelist.txt filelist.txtfile output_train_video_0.mp4 file output_train_video_1.mp4 file output_train_video_2.mp4 file output_train_video_3.mp4 file output_train_video_4.m…

android 资源文件混淆

AGP7.0以上引用AndResGuard有坑 记录下 在项目的build.gradle中添加如下 buildscript {ext.kotlin_version "1.4.31"repositories {google()jcenter()maven {url "https://s01.oss.sonatype.org/content/repositories/snapshots/"}}dependencies {class…

2023护网行动经验分享(2024护网招人)

今年的护网又开始摇人了&#xff0c;不知道大家有想法没&#xff1f; 去年的护网结束之后&#xff0c;朋友圈感觉是在过年&#xff0c;到处是倒计时和庆祝声。 看得出来防守方们7*24小时的看监控还是比较无奈的。 本次复盘基于我对整个护网行动的观察总结而来&#xff0c;仅…