【数据结构】二叉树的实现

目录

  • 1. 前言
  • 2. 二叉树的实现
    • 2.1 创建一棵树
    • 2.2 前序遍历
      • 2.2.1 分析
      • 2.2.2 代码实现
      • 2.2.3 递归展开图
    • 2.3 中序遍历
      • 2.3.1 分析
      • 2.3.2 代码实现
      • 2.3.3 递归展开图
    • 2.4 后序遍历
      • 2.4.1 分析
      • 2.4.2 代码实现
      • 2.4.3 递归展开图
    • 2.5 求节点个数
      • 2.5.1 分析
      • 2.5.2 代码实现
    • 2.6 求叶子节点个数
      • 2.6.1 分析
      • 2.6.2 代码实现
    • 2.7 求树高度
      • 2.7.1 分析
      • 2.7.2 代码实现
    • 2.8 求第K层节点的个数
      • 2.8.1 分析
      • 2.8.2 代码实现

1. 前言

在前面的博客中写了有关二叉树的介绍,那这次来写关于用C语言来实现与二叉树有关的一些操作。
与之前链表和顺序表不同的是,这里不实现增删查改。

2. 二叉树的实现

2.1 创建一棵树

直接手动创建一棵树,也就是直接malloc所有的节点。
在这里插入图片描述
直接创建6个节点,然后让node1的数据直接是1,让node2的数据直接是2,依次下去。
然后直接让node1的left = node2,它的right = node4;就按照上面的图来构建。
代码如下:

typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}TreeNode;TreeNode* CreateTree()
{TreeNode* node1 = (TreeNode*)malloc(sizeof(TreeNode));assert(node1);TreeNode* node2 = (TreeNode*)malloc(sizeof(TreeNode));assert(node2);TreeNode* node3 = (TreeNode*)malloc(sizeof(TreeNode));assert(node3);TreeNode* node4 = (TreeNode*)malloc(sizeof(TreeNode));assert(node4);TreeNode* node5 = (TreeNode*)malloc(sizeof(TreeNode));assert(node5);TreeNode* node6 = (TreeNode*)malloc(sizeof(TreeNode));assert(node6);node1->data = 1;node2->data = 2;node3->data = 3;node4->data = 4;node5->data = 5;node6->data = 6;node1->left = node2;node1->right = node4;node2->left = node3;node2->right = NULL;node3->left = NULL;node3->right = NULL;node4->left = node5;node4->right = node6;node5->left = NULL;node5->right = NULL;node6->left = NULL;node6->right = NULL;
}

但是这个代码局限性太大,已经是写固定了的代码,不好再修改,下面这种会好一些。
不用管空。
想要其它形状的可以修改代码,做一定的增加或者就行。
代码如下:

TreeNode* BuyTreeNode(int x)
{TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));assert(node);node->data = x;node->left = NULL;node->right = NULL;return node;
}TreeNode* CreateTree()
{TreeNode* node1 = BuyTreeNode(1);TreeNode* node2 = BuyTreeNode(2);TreeNode* node3 = BuyTreeNode(3);TreeNode* node4 = BuyTreeNode(4);TreeNode* node5 = BuyTreeNode(5);TreeNode* node6 = BuyTreeNode(6);node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;return node1;
}

2.2 前序遍历

2.2.1 分析

前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
在这里插入图片描述
就实现这颗树的前序遍历。
先根,然后左子树,再右子树,初学时把NULL也带上,方便理解。
也就是下面这样。
在这里插入图片描述
先访问根,然后找左子树,左子树又得拆成根和左子树,一直到空。使用递归来实现。

2.2.2 代码实现

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

结果和分析的一样:
在这里插入图片描述

2.2.3 递归展开图

在这里插入图片描述

2.3 中序遍历

2.3.1 分析

中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
同样以上面那棵树为例子。
先左子树,再根,再右子树。
在这里插入图片描述
这里遇到根先不是NULL,先走它的左子树,是空就打印返回。

2.3.2 代码实现

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

结果与分析的是一样的:
在这里插入图片描述

2.3.3 递归展开图

在这里插入图片描述

2.4 后序遍历

2.4.1 分析

.后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。
同样是以上面那棵树为例子,它的后序遍历就是:
在这里插入图片描述
先访问它的左子树,然后右子树,最后才是根。
要当左右都为空时才访问第一个节点。

2.4.2 代码实现

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

在这里插入图片描述

递归展开方式也是一样的

2.4.3 递归展开图

在这里插入图片描述

2.5 求节点个数

2.5.1 分析

只要节点不为空,就加加,然后再调用左子树,右子树。
用全局的size,每次调用前先置空一些。
局部的使用不了,因为不能置空,再调用一次就会再上次的基础上累计。
在这里插入图片描述
同样是这课树节点数为6。

2.5.2 代码实现

int size = 0;
void TreeSize(TreeNode* root)
{if (root == NULL)return;++size;TreeSize(root->left);TreeSize(root->right);
}int main()
{  TreeNode* root = CreateTree();size = 0;TreeSize(root);printf("TreeSize:%d\n", size);return 0;
}

在这里插入图片描述
还有另一种实现:把树拆成左子树加右子树加1.
代码如下:

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

结果还是一样的。
在这里插入图片描述
采用的就是分治法

2.6 求叶子节点个数

2.6.1 分析

先得判断一下树是不是空树,不是才能就行进行。
不是空树,而且左右节点都为空,就是叶子节点,就返回1;
不是空,也不是叶子节点就采用分治,树的节点就等于左右叶子节点的和。
在这里插入图片描述
在这里插入图片描述
同样是这棵树,叶子节点就是3.

2.6.2 代码实现


int TreeLeafSize(TreeNode* root)
{// 空 返回0if (root == NULL)return 0;// 不是空,是叶子 返回1if (root->left == NULL&& root->right == NULL)return 1;// 不是空 也不是叶子  分治=左右子树叶子之和return TreeLeafSize(root->left) +TreeLeafSize(root->right);
}
int main()
{TreeNode* root = CreateTree();printf("TreeLeafSize:%d\n", TreeLeafSize(root))return 0;
}

和分析的一样叶子节点个数就是3.
在这里插入图片描述

2.7 求树高度

2.7.1 分析

先要判断一下树是不是空树,是就为0。
不是空树,就要判断一下左子树和右子树那个更高,然后高的那个就加1。
在这里插入图片描述
同样以这棵树计算,这棵树的高度就是3

2.7.2 代码实现

int TreeHeight(TreeNode* root)
{if (root == NULL)return 0;int leftHeight = TreeHeight(root->left);int rightHeight = TreeHeight(root->right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}int main()
{TreeNode* root = CreateTree();printf("TreeHeight:%d\n", TreeHeight(root));return 0;
}

在这里插入图片描述


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

这里使用fmax返回大的数,需要包一个头文件<math.h>
结果也是一样的。

2.8 求第K层节点的个数

2.8.1 分析

同样采用分治。
如果是空树就返回0;
如果不为空,k=1,第一层就返回1;
如果不为空,且k>1,就返回左子树的k-1层加上右子树的k-1层。

在这里插入图片描述

同样以这棵树计算,k>1就说明再第一层的下面。这棵树的第三层的节点数就是,第二层的左加第二层的右;第二层的左又转化成第一层的左加第一层的右,为空就返回0。

2.8.2 代码实现

int TreeLevelK(TreeNode* root, int k)
{assert(k > 0);if (root == NULL)return 0;if (k == 1)return 1;return TreeLevelK(root->left, k - 1)+ TreeLevelK(root->right, k - 1);
}
int main()
{TreeNode* root = CreateTree();printf("TreeLevelK:%d\n", TreeLevelK(root, 3));return 0;
}

结果如下:
在这里插入图片描述
有问题请指出,大家一起进步!

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

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

相关文章

Linux 调试器 --- g d b 使用

目录 一&#xff1a;gdb简介 二&#xff1a;示例代码 三&#xff1a;使用 1.启动gdb 2.各种指令 <1>: 查看源代码 <2>:设置断点 <3>:查看断点信息 <4>:删除断点 <5>: run <6>:逐过程调试 <7>:逐语句调试 <8>:查…

TrustZone​之在安全状态之间切换

如果处理器处于NS.EL1,而软件想要转移到S.EL1,应该如何实现呢? 要改变安全状态,无论是向上还是向下,执行都必须经过EL3,如下图所示: 前面的图表显示了在不同安全状态之间移动涉及的步骤的示例序列。逐步进行解释: 进入较高的异常级别需要一个异常。通常,此异常…

【JavaWeb】项目后端部分统一解决方案

项目后端部分统一解决方案 文章目录 项目后端部分统一解决方案一、异步响应规范格式类二、MD5加密工具类三、JwtHelper工具类四、CrosFilter过滤器 一、异步响应规范格式类 Result类 package com.pro.common;/*** 全局统一返回结果类**/ public class Result<T> {// 返…

HTML可以使用属性访问AJAX、CSS过渡、WebSocket和服务器发送事件?

最近发现一个有意思的开源库&#xff1a;Htmx 在 GitHub 的描述中: htmx 被称为“允许您直接在HTML中使用属性访问AJAX、CSS过渡、WebSocket和服务器发送事件&#xff0c;以便您可以以超文本的简洁和强大之处构建现代用户界面”。 什么是htmx&#xff1f; 简而言之&#xff0c…

相关基础知识

本文引注&#xff1a; https://zhuanlan.zhihu.com/p/447221519 1.方差 2.自协方差矩阵 3.自相关矩阵 4.互协方差矩阵 5.互相关矩阵 6.相关系数 7.自相关函数、自协方差函数与功率谱密度 8.互相关函数、互协方差函数与互功率谱密度

强大JavaScript 技巧

浏览器 01、实现全屏 当您需要将当前屏幕显示为全屏时 function fullScreen() { const el document.documentElement const rfs el.requestFullScreen || el.webkitRequestFullScreen || el.mozRequestFullScreen || el.msRequestFullscreen i…

时间选择器

<el-form-item label"时间范围"><!-- <el-date-picker size"small"v-model"createTime"type"daterange"range-separator"至"start-placeholder"请输入起始创建时间"end-placeholder"请输入终止创…

前端常见手写代码题集

1. 手写Object.create 思路&#xff1a;将传入的对象作为原型 function create(obj) {function F() { }F.prototype objreturn new F() }2. 手写 instanceof 思路&#xff1a;不断地从左边的原型链上去找 function MyInstanceof(left, right) {let l Object.getPrototype…

无线网优AP、SW发现控制器

目录 无线网优解决的问题 1、信号覆盖不足的原因 2、信道繁忙 3、非802.11干扰 4、协商速率低 5、漫游效果差 6、有线带宽阻塞 无线网优方法 交换机发现与激活 一&#xff0c;交换机发现控制器方式 1、二层广播 2、DHCP option43方式 3、DNS域名解析方式 4、trou…

Springboot之整合Swagger3

依赖 <dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version></dependency>配置 application.yaml spring:# mvc这部分解决swagger3在新版本Springboot中无…

C++模板基础及代码实战

C模板基础及代码实战 C 模板概览 泛型编程的支持 C 不仅为面向对象编程提供了语言支持&#xff0c;还支持泛型编程。正如第6章《设计可重用性》中讨论的&#xff0c;泛型编程的目标是编写可重用的代码。C 中支持泛型编程的基本工具是模板。虽然模板不严格是面向对象的特性&a…

C/C++---------------LeetCode第350. 两个数组的交集 II

两个数组的交集|| 题目及要求双指针哈希表在main内使用 题目及要求 给你两个整数数组 nums1 和 nums2 &#xff0c;请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数&#xff0c;应与元素在两个数组中都出现的次数一致&#xff08;如果出现次数不一致&#xff0…

基于springboot + vue大学生竞赛管理系统

qq&#xff08;2829419543&#xff09;获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;springboot 前端&#xff1a;采用vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xf…

基于单片机的智能健康监测手环的设计

目 录 1 绪论... 2 1.1 引言... 2 1.2 智能手环的国内外研究现状... 2 1.3 课题的研究意义... 3 1.4 本文的研究内容和章节安排... 4 2 智能手环系统设计方案... 5 2.1 系统总体设计方案... 5 2.2 主芯片选择... 5 2.3 显示方案的选择... 6 2.4 倾角传感器的选择... 6 2.5 心率…

【AIGC】AI作图最全提示词prompt集合(收藏级)

目录 一、正向和负向提示词 二、作图参数 你好&#xff0c;我是giszz. AI做图真是太爽了&#xff0c;解放生产力&#xff0c;发展生产力。 但是&#xff0c;你是不是也总疑惑&#xff0c;为什么别人的图&#xff0c;表现力那么丰富呢&#xff0c;而且指哪打哪&#xff0c;要…

DFT(离散傅里叶变换)的通俗理解

本文包含了博主对离散傅里叶变换&#xff0c;负频率&#xff0c;实信号与复信号频谱的理解&#xff0c;如有不妥&#xff0c;欢迎各位批评指正与讨论。 文章目录 DFT的理解信号的频谱实信号的频谱复信号的频谱 DFT的理解 傅里叶变换是一种将信号从时域转换到频域的数学工具。…

SQL Server事务(Transaction)

5. 事务(Transaction) 5.1. 事务概念 事务是关系库中不可分割的一系列数据库操作,这些操作必须要么整体成功,要么整体失败。事务维护数据完整性,保证数据库总是处于一致性状态。虽然,各关系库中事务实现和操作的具体细节有所不同,但基本概念和功能完全相同,而具体操作…

通信标准化协会,信通院及量子信息网络产业联盟调研玻色量子,共绘实用化量子未来!

8月14日&#xff0c;中国通信标准化协会&#xff0c;信通院标准所及量子信息网络产业联盟等单位领导走访调研北京玻色量子科技有限公司&#xff08;以下简称“玻色量子”&#xff09;&#xff0c;参观了玻色量子公司及自建的十万颗粒洁净度的光量子信息技术实验室&#x1f517;…

【win32_003】不同字符集下的通用字符串语法TCHAR、TEXT、PTSTR、PCTSTR

TCHAR 通用 根据项目属性是否使用Unicode字符集&#xff0c;TCHAR被解释为CHAR(char)或WCHAR(wchar_t)数据类型。 TCHAR a ‘A’ ; TCHAR arr [] TEXT(“AA”); TCHAR arr [100] TEXT(“AA”); TCHAR *pstr TEXT(“AA”); TEXT宏 #ifdef UNICODE #define __TEXT(quote) L#…

STM32下载程序的五种方法

刚开始学习 STM32 的时候&#xff0c;很多小伙伴满怀热情买好了各种设备&#xff0c;但很快就遇到了第一个拦路虎——如何将写好的代码烧进去这个黑乎乎的芯片&#xff5e; STM32 的烧录方式多样且灵活&#xff0c;可以根据实际需求选择适合的方式来将程序烧录到芯片中。本文将…