【数据结构】链式结构实现:二叉树
二叉树
- 一.快速创建一颗二叉树
- 二.二叉树的遍历
- 1.前序、中序、后序遍历(深度优先遍历DFS)
- 2.层序遍历(广度优先遍历BFS)
- 三.二叉树节点的个数
- 四.二叉树叶子节点的个数
- 五.二叉树的高度
- 六.二叉树第k层节点个数
- 七.二叉树查找值为x的节点
- 八.判断二叉树是否是完全二叉树
- 九.二叉树的递归创建
- 十.二叉树的销毁
- 十一.二叉树必做OJ题
- 十二.了解高级树
一.快速创建一颗二叉树
-
回顾⼆叉树的概念,⼆叉树分为空树和非空⼆叉树,非空⼆叉树由根结点、根结点的左子树、根结点的右子树组成的
-
根结点的左子树和右子树分别又是由子树结点、子树结点的左子树、子树结点的右子树组成的,因此
⼆叉树定义是递归式的
,后序链式⼆叉树的操作中基本都是按照该概念实现的。
typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;BTNode* BuyNode(BTDataType x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL){perror("malloc fail!");return;}node->data = x;node->left = node->right = NULL;return node;
}BTNode* CreatBinaryTree()
{BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;return node1;
}int main()
{BTNode* root = CreatBinaryTree();return 0;
}
二.二叉树的遍历
1.前序、中序、后序遍历(深度优先遍历DFS)
按照规则,⼆叉树的遍历有:前序/中序/后序的递归结构遍历:
-
前序遍历:访问根结点的操作发生在遍历其左右子树之前;访问顺序为:根结点、左子树、右子树
-
中序遍历:访问根结点的操作发生在遍历其左右子树中间;访问顺序为:左子树、根结点、右子树
-
后序遍历:访问根结点的操作发生在遍历其左右子树之后;访问顺序为:左子树、右子树、根结点
参考如下:
代码如下:
//前序遍历
void PrevOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}printf("%d ", root->data);PrevOrder(root->left);PrevOrder(root->right);
}//中序遍历
void InOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}//后序遍历
void PosOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}PosOrder(root->left);PosOrder(root->right);printf("%d ", root->data);
}int main()
{BTNode* root = CreatBinaryTree();PrevOrder(root);printf("\n");InOrder(root);printf("\n");PosOrder(root);printf("\n");return 0;
}
前序遍历递归图解:
注意:已知二叉树的前序和中序
,后序和中序
就可以推导出二叉树的形状,但是只知道前序和后序则无法推导
出二叉树的形状。
2.层序遍历(广度优先遍历BFS)
层序遍历:除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根结点所在层数为1,层序遍历就是从所在二叉树的根结点出发,首先访问第一层的树根结点,然后从左到右访问第2层上的结点,接着是第三层的结点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
实现层序遍历需要用到队列,拷贝Queue.h与Queue.c文件到本地。
void TreeLevelOrder(BTNode* root)
{Queue q;QueueInit(&q);if(root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);printf("%d ", front->val);// NULL无需入队列if(front->left)QueuePush(&q, front->left);if (front->right)QueuePush(&q, front->right);}QueueDestory(&q);
}
三.二叉树节点的个数
错误写法:
改进方法:
最好的方法:分治法(大问题化为多个小问题、小问题再化为多个小问题…直到不能再分为止)
- 空:0个
- 非空:左子树+右子树+1
int TreeSize(BTNode* root)
{if (root == NULL)return 0;return TreeSize(root->left) + TreeSize(root->right) + 1;
}
四.二叉树叶子节点的个数
- 空:0个
- 非空:若左子树和右子树同时为空返回1,否则左子树叶子节点+右子树叶子节点
int TreeLeafSize(BTNode* root)
{if (root == NULL)return 0;if (root->left == NULL && root->right == NULL)return 1;return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}
五.二叉树的高度
- 空:0个
- 非空:MAX {左子树高度,右子树高度} + 1
//未记录高度导致重复大量的递归效率极低
//int TreeHeight1(BTNode* root)
//{
// if (root == NULL)
// return 0;
//
// return TreeHeight(root->left) > TreeHeight(root->right) ?
// TreeHeight(root->left) + 1 : TreeHeight(root->right) + 1;
//}int TreeHeight(BTNode* root)
{if (root == NULL)return 0;int leftHeight = TreeHeight(root->left);int rightHeight = TreeHeight(root->left);return leftHeight > rightHeight ?leftHeight + 1 : rightHeight + 1;
}
六.二叉树第k层节点个数
- 空:0个
- 非空且k==1:返回1
- 非空且k>1:左子树的k-1层节点个数+右子树的k-1层节点个数
int TreeLevelKSize(BTNode* root, int k)
{if (root == NULL)return 0;if (k == 1)return 1;return TreeLevelKSize(root->left, k - 1) + TreeLevelKSize(root->right, k - 1);
}
七.二叉树查找值为x的节点
- 空:返回NULL
- 非空且data==x:返回root
- 非空且data!=x:递归左子树+递归右子树,注意:
要保存递归的结果层层返回
BTNode* TreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->data == x)return root;BTNode* ret1 = TreeFind(root->left, x);if (ret1)return ret1;BTNode* ret2 = TreeFind(root->right, x);if (ret2)return ret2;return NULL;
}
八.判断二叉树是否是完全二叉树
注意
:满二叉树可以利用树的高度,和节点的个数判断,但是完全二叉树前k-1层是满二叉树,最后一层不是满的,该方法就不行了。
可以利用层序遍历解决,方法如下:
bool TreeComplete(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){QueueDestory(&q);return false;} }//队列中没有非空节点,就是完全二叉树QueueDestory(&q);return true;
}
九.二叉树的递归创建
题目:已知前序遍历结果:abc##de#g##f###
(其中#是NULL)
输出:中序遍历的结果(不包含NULL)
#include <stdio.h>
#include<stdlib.h>typedef struct BinaryTreeNode
{char val;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;BTNode* CreateTree(char* a, int* pi)
{//遇到#返回NULLif(a[*pi] == '#'){(*pi)++;return NULL;}//创建根节点BTNode* root = (BTNode*)malloc(sizeof(BTNode));root->val = a[(*pi)++];//递归构建左子树root->left = CreateTree(a, pi);//递归构建右子树root->right = CreateTree(a, pi);//返回根节点return root;
}void InOrder(BTNode* root)
{if(root == NULL)return;InOrder(root->left);printf("%c ", root->val);InOrder(root->right);
}int main() {char a[100];scanf("%s", a);int i = 0;BTNode* root = CreateTree(a, &i); //注意:要传入地址InOrder(root);
}
十.二叉树的销毁
- 空:返回NULL
- 非空:后序遍历销毁节点
void TreeDestory(BTNode* root)
{if (root == NULL)return;TreeDestory(root->left);TreeDestory(root->right);free(root);
}
十一.二叉树必做OJ题
- 单值二叉树
- 相同的树
- 对称二叉树
- 二叉树的前序遍历
- 二叉树的中序遍历
- 二叉树的后序遍历
- 另一棵树的子树
- 二叉树遍历
十二.了解高级树
相关文章:

【数据结构】链式结构实现:二叉树
二叉树 一.快速创建一颗二叉树二.二叉树的遍历1.前序、中序、后序遍历(深度优先遍历DFS)2.层序遍历(广度优先遍历BFS) 三.二叉树节点的个数四.二叉树叶子节点的个数五.二叉树的高度六.二叉树第k层节点个数七.二叉树查找值为x的节点…...

20221元组
在Python语言中, (7)是一种可变的、有序的序列结构,其中元素可以重复。 A.元组(tuple) B. 字符串(str) C. 列表(list) D.集合(set) ChatGPT 说: ChatGPT 在Python中,选项 C 列表(list) 符合题目描述。 解释: 列表 (list) 是一种可变的、有…...

艾瑞白皮书解读(三)丨剖析制造业、工程设计、创投数据治理痛点与典型方案
2024年7月 艾瑞咨询公司对国内数据治理行业进行了研究,访问了国内多位大中型企业数据治理相关负责人,深度剖析中国企业在数字化转型过程中面临到的核心数据问题后,重磅发布《2024中国企业数据治理白皮书》(以下简称“白皮书”&…...

如何在 Odoo 16 Studio 模块中自定义视图和报告
为了有效地运营公司,需要定制的软件系统。Odoo 平台提供针对单个应用程序量身定制的管理解决方案和用户友好的界面,以便开发应用程序,而无需更复杂的后端功能。该平台支持使用简单的拖放功能和内置工具创建和修改更多定制的 Odoo 应用程序。企…...

Redis的十大数据类型的常用命令(上)
目录 1.key的操作命令2.String的常用命令案例一:dy点赞案例二:文章的喜欢数 3. List的常用命令案例:公众号订阅的消息 4. Hash的常用命令案例:早期购物车设计 5. Set的常用命令案例一:抽奖小程序案例二:朋友…...
智慧服务管理平台小程序开发方案
智慧服务管理平台小程序系统为用户提供一站式、个性化的服务管理解决方案,帮助用户优化服务流程、提升服务效率、增强客户满意度。适用于智慧校园、食堂、养老、智慧停车、智慧园区、智慧医院、智慧农业、康养、智慧社区、智慧农场等行业场景。一、目标用户 企业客户…...

【轻松拿捏】Java中ArrayList 和 LinkedList 的区别是什么?
ArrayList 和 LinkedList 的区别是什么? 1. ArrayList 2. LinkedList 3.总结 🎈边走、边悟🎈迟早会好 ArrayList 和 LinkedList 都是 Java 中常用的 List 接口的实现类,但它们在内部结构和操作性能上有所不同。 1. ArrayLis…...

【排序篇】快速排序的非递归实现与归并排序的实现
🌈个人主页:Yui_ 🌈Linux专栏:Linux 🌈C语言笔记专栏:C语言笔记 🌈数据结构专栏:数据结构 文章目录 1 快速排序非递归2. 归并排序3.排序算法复杂度及稳定性分析 1 快速排序非递归 利…...
Java垃圾收集器工作原理
在Java编程中,对象的内存分配主要发生在堆(Heap)上。堆是Java虚拟机(JVM)中的一块运行时数据区,用于存放由new关键字创建的对象和数组。与栈(Stack)内存分配相比,堆内存分…...

STM32CubeMX stm32不限长度使用DMA收发串口数据
STM32CubeMX 配置 代码 stm32h7xx_it.c /*** brief This function handles UART7 global interrupt.*/ void UART7_IRQHandler(void) {/* USER CODE BEGIN UART7_IRQn 0 */if (UART7 huart7.Instance) // 判断是否是空闲中断{if (__HAL_UART_GET_FLAG(&huart7, UART_FLA…...

Jmeter系列之作用域、执行顺序
这一节主要解释元件作用域和执行顺序,以及整理之前说过的参数化的方式。 作用域 之前也留下了一个问题。怎么给不同的请求设置不同的Header?后续也透露了可以使用Sample Controller,结合元件的作用域来实现 在Jmeter中,元件的作…...

舜宇光学科技社招校招入职测评:商业推理测验真题汇总、答题要求、高分技巧
舜宇光学科技(集团)有限公司,成立于1984年,是全球领先的综合光学零件及产品制造商。2007年在香港联交所主板上市,股票代码2382.HK。公司专注于光学产品的设计、研发、生产及销售,产品广泛应用于手机、汽车、…...
C语言——构造(结构体)
指针——内存操作 我们对于内存的操作借助于 <string.h>这个库提供的内存操作函数。 内存填充 头文件: #include<string.h> 函数原型: void*memset(void *s,int c,size_t n); 函数功能: 填充s开始的堆内存空间前n个字节,使得每个字节值为c…...

京东2025届秋招 算法开发工程师 第2批笔试
目录 1. 第一题2. 第二题3. 第三题 ⏰ 时间:2024/08/17 🔄 输入输出:ACM格式 ⏳ 时长:2h 本试卷还有选择题部分,但这部分比较简单就不再展示。 1. 第一题 村子里有一些桩子,从左到右高度依次为 1 , 1 2…...

模具监视器的技术参数有哪些
模具监视器的技术参数涵盖了多个方面,这些参数对于确保模具监视器的性能、稳定性和检测精度至关重要。以下是一些主要的技术参数: 一、显示器参数 屏幕尺寸:常见的模具监视器显示器尺寸为12.5英寸至13.5英寸,具体尺寸可能因不同…...

使用QGIS配置管线流向地图
一、需求概述 在管网项目中,需要进行地图配置使用QGIS显示管网的流向。 二、目标 配置一副管网地图,可以在地图上显示出每个管段的流向。 三、数据结构 管网数据: id[管线编码]source[起始节点ID]target[终点节点ID]dir[方向]1100101FT2101102FT……………………节点数据…...
白骑士的C#教学附加篇 5.1 C#开发工具
系列目录 上一篇:白骑士的C#教学实战项目篇 4.4 游戏开发 在这一部分,我们将介绍一些额外的内容和工具,以帮助您提高 C# 开发的效率和质量。掌握合适的开发工具和调试技巧,可以让您在编写和维护代码时更加高效和从容。 开发工具对…...
C++中的多线程编程和锁机制
二、多线程、锁 2.1 C语言线程库pthread(POSIX threads) 2.2.1 线程创建 pthread_create #include <pthread.h>pthread_t thread; ThreadData args {1, "Hello from parameterized thread"}; int result pthread_create(&threa…...

【投融界-注册安全分析报告】
前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞…...

自动打电话软件给企业带来了什么?
使用机器人外呼系统肯定都是想要给自己企业带来好处和解决问题的,想让自己的企业有所改变,有更好的发展,所以才会选择使用机器人外呼系统。而它也确实没让大家失望,使用了机器人外呼系统之后确实有许多企业发生了很大改变和进步&a…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...