二叉树--C语言实现数据结构

在这里插入图片描述

本期带大家一起用C语言实现二叉树🌈🌈🌈

1、二叉树的定义

二叉树是一种特殊的树状数据结构,它由节点组成,每个节点最多有两个子节点,分别称为左子节点和右子节点

二叉树的链式存储结构是指用 链表 来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三

个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址

2、二叉树 的结构

在这里插入图片描述

3、二叉树的实现

3.1 结构设计

typedef int BTreeDataType;typedef struct BTreeNode
{BTreeDataType val;struct BTreeNode* right;struct BTreeNode* left;
}BTNode;

3.2 手动构建二叉树

在这里插入图片描述

BTNode* CreatNode(BTreeDataType val)
{BTNode* root = (BTNode*)malloc(sizeof(BTNode));if (root == NULL){perror("root malloc fail");return;}root->val = val;root->left = NULL;root->right = NULL;return root;}
BTNode* CreatBinaryTree()
{BTNode* root1 = CreatNode(1);BTNode* root2 = CreatNode(2);BTNode* root3 = CreatNode(3);BTNode* root4 = CreatNode(4);BTNode* root5 = CreatNode(5);BTNode* root6 = CreatNode(6);BTNode* root7 = CreatNode(7);root1->left = root2;root1->right = root3;root2->left = root4;root2->right = root5;root3->left = root6;root3->right = root7;return root1;}

3.3 前序遍历

  1. 首先进行条件判断,如果当前节点root为空,即遍历到了空节点,输出"N "(表示Null)之后返回。这是因为在先序遍历中,空节点也需要被遍历到。

  2. 若当前节点root不为空,则输出当前节点的值root->val

  3. 继续递归遍历当前节点的左子树,即调用PrevOrder(root->left)

  4. 最后,递归遍历当前节点的右子树,即调用PrevOrder(root->right)

通过递归的方式,先序遍历会按照先根节点、左子树、右子树的顺序遍历整个二叉树。在代码中,先打印当前节点的值,然后分别遍历左子树和右子树。

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

在这里插入图片描述

3.4 中序遍历

  1. 首先进行条件判断,如果当前节点root为空,即遍历到了空节点,输出"N "(表示Null)之后返回。这是因为在中序遍历中,空节点也需要被遍历到。

  2. 若当前节点root不为空,则递归遍历当前节点的左子树,即调用InOrder(root->left)

  3. 输出当前节点的值root->val

  4. 最后,递归遍历当前节点的右子树,即调用InOrder(root->right)

通过递归的方式,中序遍历会按照左子树、根节点、右子树的顺序遍历整个二叉树。在代码中,先遍历左子树,然后打印当前节点的值,最后遍历右子树。这样可以保证中序遍历的顺序性。

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

3.5 后序遍历

后序遍历的访问次序是 先访问左子树,再访问右子树,再访问根节点

逻辑同前序遍历和中序遍历差不多

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

3.4 层序遍历

层序遍历就是从第一层开始从左向右逐个遍历

那么当前结果就是1 2 3 4 5 6 7

层序遍历的话,需要一个队列来进行辅助

首先我们将root根节点放进去,然后判断队列当中是否为空,为空就跳出循环

不为空的话就将节点不为NULL的放进去,直到队列为空

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

核心思想就是出上一层带下一层

3.5 计算二叉树的节点数

这里我们可以有两种思路:
1、给定一个 size ,遍历二叉树,分别遍历左右子树,遍历过程中遍历到非空节点 size++,遍历到空,则返回 0。
2、二叉树的大小 = 根节点 + 左子树节点 + 右子树节点,将其分成多个子问题,递归求解。

思路1 size计数

使用局部变量size来记录节点数量是不可行的。因为在递归调用的过程中,每一次递归都会创建一个新的函数栈帧,这意味着每个递归调用都有自己独立的size变量,并且初始值都是0,无法准确计算出二叉树的大小。

为了解决这个问题,可以使用全局变量size来记录节点数量。全局变量位于全局数据区,在整个工程内都有效。但需要注意的是,由于全局变量不会被销毁,如果多次调用计算节点数量的函数,size会累加,可能导致错误的结果。因此,在每次调用之前,需要将size重置为0,以确保准确计算二叉树的大小。

总结来说,局部变量不能满足统计二叉树节点数量的在这里插入代码片需求,需要使用全局变量,并在每次调用之前将其重置为0。

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

思路2 递归实现
计算二叉树的节点数

如果root==NULL的话,那我们就返回0

不然的话我们就返回1+左子树的节点树+右子树的节点数

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

3.6 计算二叉树的高度

计算二叉树的高度

如果我们的root==NULL的话,那我们返回0

不然的话计算左子树的高度和右子树的高度

让最高的子树高度+1就是我们的二叉树高度

不过需要注意的是需要拿left_height和right_height来计数,防止重复递归调用

不然到时候还得重复计算好多次,尤其是会重复计算下面的高度

可不是简单的二倍关系

nt BTreeHeight(BTNode* root)
{if (root == NULL)return 0;int left_hight = BTreeHeight(root->left);int right_hight = BTreeHeight(root->right);return left_hight > right_hight ?  1 + left_hight : 1 + right_hight;
}

3.7 计算叶子节点的个数

计算叶子节点的个数

如果root==NULL,返回0

如果root->left == NULL && root->right == NULL 那就返回1

如果还不满足以上的条件话,那就返回左子树的叶子节点个数+右子树叶子节点个数

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

3.8 计算第K层节点数

计算第K层节点数

对于第一层,需要计算的是 第 k 层的节点个数;
对于第二层,需要计算的是 第 k - 1 层的节点个数;
对于第 k 层,计算的就是 第 1 层( 当前层数 ) 的节点个数。

如果我的root==NULL的话,那就返回0

如果我的root!=NULL而且k==1的话那就返回1

不然的话就返回左子树第k-1层节点的数目+右子树第k-1层节点的数目

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

3.9 查找某个值对应的节点

查找某个值对应的节点

如果root==NULL,返回NULL

如果root->val==val,返回root

既然root->val!=val,那么就去左右子树分别查找

如果在左子树查走到了,那么就返回左子树当中找到的那个节点

如果在右子树查走到了,那么就返回右子树当中找到的那个节点

至于为什么要判断左右子树查找到结果不为NULL呢

因为左子树如果结果是NULL,不然直接返回NULL

还有右子树没有查找

右子树的结果的话可以不用判NULL,因为这个时候根节点和左子树当中都没有找到val,那么就剩下右子树了

如果右子树还没有的话,那就没有,返回NULL,有的话就返回节点

BTNode* BTreeFind(BTNode* root, BTreeDataType val)
{if (root == NULL)return NULL;if (root->val == val)return root;BTNode* leftNode = BTreeFind(root->left,val);if (leftNode != NULL)return leftNode;BTNode* rightNode = BTreeFind(root->right, val);if (rightNode != NULL)return rightNode;return NULL;}

3.10 判断是否为满二叉树

和层序遍历的思想一样,需要一个队列来进行辅助

首先将根节点root放到队列当中
如果在中途遇到了NULL的话,那就跳出循环
如果没遇到NULL的话,那就带下一层子树进来

遇到NULL结束入队列,并且检查队列当中是否还有有效元素(NULL除外)

如果全是NULL,那就代表这个二叉树完全二叉树

不然的话就不是

bool IsComplete(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 != NULL){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}

3.11 二叉树的销毁

二叉树的销毁逻辑是和后序遍历一样的

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

4、感谢与交流✅

🌹🌹🌹如果大家通过本篇博客收获了,对二叉树有了新的了解的话
那么希望支持一下哦如果还有不明白的,疑惑的话,或者什么比较好的建议的话,可以发到评论区,
我们一起解决,共同进步 ❗️❗️❗️
最后谢谢大家❗️❗️❗️💯💯💯

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

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

相关文章

【数据结构】二叉树详解(1)

⭐️ 前言 ✨ 二叉树的概念性质 ⭐️ 二叉树链式结构的实现 结构定义&#xff1a; #include <stdio.h> #include <stdlib.h> #include <assert.h>typedef int BinaryTreeDataType;typedef struct BinaryTreeNode {BinaryTreeDataType value;struct Binary…

【Python统计与数据分析实战_01】位置与分散程度的度量

数据描述性分析 1.描述统计量1.1 位置与分散程度的度量1.1.1 例子一 单维数组1.1.2 例子二 多维数组 1.2 关系度量1.3 分布形状的度量1.3.1 统计量&#xff1a;偏度和峰度 1.4 数据特性的总括 1.描述统计量 数据的统计分析分为统计描述和统计推断两部分。前者通过绘制统计图、…

港联证券-尾盘集合竞价拉升意味着什么意思?

在股票市场中&#xff0c;尾盘集合竞价是指每个交易日的最后几分钟&#xff0c;即下午14:57到3:00之间的交易。在这段时间内&#xff0c;所有股票的买卖都将以竞价的方式进行&#xff0c;最终价格以最高买价与最低卖价的平均值确定&#xff0c;成交量也将作为当日的收盘价和成交…

Django实现接口自动化平台(十三)接口模块Interfaces序列化器及视图【持续更新中】

相关文章&#xff1a; Django实现接口自动化平台&#xff08;十二&#xff09;自定义函数模块DebugTalks 序列化器及视图【持续更新中】_做测试的喵酱的博客-CSDN博客 本章是项目的一个分解&#xff0c;查看本章内容时&#xff0c;要结合整体项目代码来看&#xff1a; pytho…

SQL语句GROUP BY、HAVING、EXISTS、SQL函数(Null判断、日期相关、计算数值和字符串操作 )

目录 GROUP BY HAVING EXISTS SQL函数 Null判断函数 日期数据类型及函数 计算数值和字符串操作函数 AVG(平均值) COUNT(数据条数) FIRST/LAST(第一条数据) MAX/MIN(最大值) SUM(列总和) UCASE/ LCASE (转换大小写) MID(截取字符串) LEN(字符值的长度) ROUND(数…

学习记录——SpectFormer、DilateFormer、ShadowFormer

SpectFormer: Frequency and Attention is what you need in a Vision Transformer, arXiv2023 频域混合注意力SpectFormer 2023 论文&#xff1a;https://arxiv.org/abs/2304.06446 代码&#xff1a;https://badripatro.github.io/SpectFormers/ 摘要视觉变压器已经成功地应用…

nginx基础2——配置文件详解(网页配置篇)

文章目录 一、基本了解二、nginx.conf配置参数2.1 调试参数2.2 必配参数2.3 优化性能参数2.4 event{}段配置参数2.5 网络连接参数2.6 fastcgi配置参数2.7 总结常配参数 三、http{}段配置参数3.1 配置结构3.2 精简配置网页3.3 location定义网页3.3.1 root path用法3.3.1 alias p…

哪些方法可以一键批量查询快递单号

想做好电商或者物流行业&#xff0c;可千万不能虎头蛇尾&#xff0c;前端的高效并不够&#xff0c;我们还要做好后端的及时跟踪维护。当大量快递集中发出之后&#xff0c;我们必须及时地跟踪物流信息&#xff0c;掌握快递的动态&#xff0c;小编今天要和大家安利一款实用的辅助…

Linux系统部署Tomcat详细教程(图文讲解)

前言&#xff1a;本篇博客教大家如何一步一步使用Linux系统去部署自己的Tomcat服务器&#xff0c;每一行代码都是我自己严格执行过的&#xff0c;共分为了8点进行阐述&#xff0c;逻辑清晰&#xff01; 目录 一、安装JDK环境 二、准备Tomcat安装包 三、安装Tomcat 四、配置…

Nuxt.js--》解密Nuxt.js:构建优雅、高效的现代化Vue.js应用

博主今天开设Nuxt.js专栏&#xff0c;带您深入探索 Nuxt.js 的精髓&#xff0c;学习如何利用其强大功能构建出色的前端应用程序。我们将探讨其核心特点、灵活的路由系统、优化技巧以及常见问题的解决方案。无论您是想了解 Nuxt.js 的基础知识&#xff0c;还是希望掌握进阶技巧&…

精智达在科创板上市:募资约11亿元,深创投等为其股东

7月18日&#xff0c;深圳精智达技术股份有限公司&#xff08;下称“精智达”&#xff0c;SH:688627&#xff09;在上海证券交易所科创板上市。本次上市&#xff0c;精智达的发行价为46.77元/股&#xff0c;发行数量为2350.2939万股&#xff0c;募资总额为10.99亿元&#xff0c;…

10-2. 数组 Array 的实例方法

本文并没有写出数组的全部使用方法&#xff0c;想看全的可以看一下这个 Array - JavaScript | MDN 目录 1 常用内置方法 1.1 合并数组 concat() 1.2 复制元素覆盖到指定位置 copyWithin() 1.3 返回其他变量的数组形式 Array.from() 1.3.1 基本使用 1.3.2 将伪数组…