【数据结构】拆分详解 - 二叉树的链式存储结构
文章目录
- 一、前置说明
- 二、二叉树的遍历
- 1. 前序、中序以及后序遍历
- 1.1 前序遍历
- 1.2 中序遍历
- 1.3 后序遍历
- 2. 层序遍历
- 三、常见接口实现
- 0. 递归中的分治思想
- 1. 查找与节点个数
- 1.1 节点个数
- 1.2 叶子节点个数
- 1.3 第k层节点个数
- 1.4 查找值为x的节点
- 2. 二叉树的创建与销毁
- 2.1 创建
- 2.2 销毁
- 总结
一、前置说明
在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。由于现在大家对二叉树结构掌握还不够深入,为了降低大家学习成本,此处手动快速创建一棵简单的二叉树,快速进入二叉树操作学习,等二叉树结构了解的差不多时,我们反过头再来研究二叉树真正的创建方式。
注意:下述代码并不是创建二叉树的方式,真正创建二叉树方式文章末尾处会进行讲解。
typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType _data;struct BinaryTreeNode* _left;struct BinaryTreeNode* _right;
}BTNode;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;
}
二、二叉树的遍历
1. 前序、中序以及后序遍历
学习二叉树结构,最简单的方式就是遍历。所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的所有节点进行访问。
按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历,区别为访问根的顺序不同。
- 前序遍历 :访问顺序为根,左子树,右子树
- 中序遍历:访问顺序为左子树,根,右子树
- 后序遍历:访问顺序为左子树,右子树,根
1.1 前序遍历
void BinaryTreePrevOrder(BTNode* root)
{//为空if (root == NULL){printf("N ");return ;}//不为空,打印节点值,继续找左子树,找完后找右子树printf("%d ", root->data);BinaryTreePrevOrder(root->left);BinaryTreePrevOrder(root->right);
}
1.2 中序遍历
void BinaryTreeInOrder(BTNode* root)
{//为空if (root == NULL){printf("N ");return;}//左BinaryTreeInOrder(root->left);//根printf("%d ", root->data);//右BinaryTreeInOrder(root->right);
}
1.3 后序遍历
void BinaryTreePostOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}BinaryTreePostOrder(root->left);BinaryTreePostOrder(root->right);printf("%d ", root->data);
}
2. 层序遍历
除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
三、常见接口实现
0. 递归中的分治思想
在下面的接口实现中我们使用递归实现分治思想(将大问题拆分成多个子问题处理),我们要注意如何拆分子问题 和 表达递归的结束条件。
- 递归:分为递推和回归。我们可以画递推展开图,假想递推到底的情况,思考分析回归条件,可代入回归检验是否符合。
- 分治:将问题抽象分为多个子问题,分别解决
- 用递归实现分治 :一路递推到底,处理完第一个子问题,回归,在回归过程中处理之前未处理的子问题。(子问题可能会被处理多次,但每个子问题的处理次数总和一定是相同的,只是处理先后的不同)本质是将问题的核心基础步骤抽象出来,使用递归方式重复处理,最终达成目的。
1. 查找与节点个数
1.1 节点个数
子问题分治:节点个数 = 左子树节点个数 + 右子树节点个数
递归(结束)返回条件:
- 空 返回 0
- 不为空 返回1
int BinaryTreeSize(BTNode* root)
{//如果根为空就返回0,否则返回左子树与右子树节点数和return root == NULL ? 0 : BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}
1.2 叶子节点个数
子问题分治:节点个数 = 左子树叶子节点个数 + 右子树叶子节点个数
递归(结束)返回条件:
- 空 返回 0
- 叶子 返回1
int BinaryTreeLeafSize(BTNode* root)
{//单独判断空树if (root == NULL){return 0;}//如果左子树和右子树都不为空,说明为叶子if (!root->left && !root->right){return 1;}return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}
1.3 第k层节点个数
子问题分治:第k层节点个数 = 第k-1层的左子树节点个数 + 第k-1层的右子树节点个数
递归(结束)返回条件:
- 空 返回 0
- 不为空且为k层 返回1
int BinaryTreeLevelKSize(BTNode* root, int k)
{assert(k> 0);if (root == NULL)return 0;//不为空且为k层,返回1if (k == 1)return 1;//k == 1 说明为k层,不为则继续向下递推return BinaryTreeLevelKSize(root->left, k-1) + BinaryTreeLevelKSize(root->right, k-1);
}
1.4 查找值为x的节点
子问题分治:查找 = 查找左子树 + 查找右子树
递归(结束)返回条件:
- 空 返回 0
- 找到 返回节点地址
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->data == x)return root;//使用指针变量存储地址,若不为空说明找到,不需要进行其他操作,使其一路回归BTNode* ret1 = BinaryTreeFind(root->left, x);if (ret1)return ret1;BTNode* ret2 = BinaryTreeFind(root->right, x);if (ret2)return ret2;return NULL;
}
2. 二叉树的创建与销毁
2.1 创建
子问题分治:创建 = 创建左子树 + 创建右子树
递归(结束)返回条件:
- 空(‘#’) 返回NULL
- 非空 创建节点并初始化
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
// a为数组,pi为 外部中标识数组下标变量的 指针
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{if (a[*pi] == '#'){*pi++; //下标后移return NULL;}BTNode* root = (BTNode*)malloc(sizeof(BTNode));if (root == NULL){perror("malloc fail");exit(-1);}root->data = a[*pi];root->left = BinaryTreeCreate(a, n, ++*pi);root->right = BinaryTreeCreate(a, n, ++ * pi);
}
2.2 销毁
void BinaryTreeDestory(BTNode** root)
{if (*root == NULL){return;}BinaryTreeDestory((*root)->left);free(*root);BinaryTreeDestory((*root)->right);free(*root);free(*root);*root == NULL;
}
总结
知识框架可看文章目录。
本文讲解了二叉树的链式存储结构的相关知识,递归和分治思想十分抽象,需要读者自行画递归展开图理解,多练习,培养出自己的抽象能力。
文章中有什么不对的丶可改正的丶可优化的地方,欢迎各位来评论区指点交流,博主看到后会一一回复。
相关文章:
【数据结构】拆分详解 - 二叉树的链式存储结构
文章目录 一、前置说明二、二叉树的遍历 1. 前序、中序以及后序遍历 1.1 前序遍历 1.2 中序遍历 1.3 后序遍历 2. 层序遍历 三、常见接口实现 0. 递归中的分治思想 1. 查找与节点个数 1.1 节点个数 1.2 叶子节点个数 1.3 第k层节…...
Laravel修改默认的auth模块为md5(password+salt)验证
首先声明:这里只是作为一个记录,实行拿来主义,懒得去记录那些分析源码的过程,不喜勿喷,可直接划走。 第一步:创建文件夹:app/Helpers/Hasher; 第二步:创建文件: app/Help…...

OpenStack-train版安装之安装Keystone(认证服务)、Glance(镜像服务)、Placement
安装Keystone(认证服务)、Glance(镜像服务)、Placement 安装Keystone(认证服务)安装Glance(镜像服务)安装Placement 安装Keystone(认证服务) 数据库创建、创…...
【九日集训】第九天:简单递归
递归就是自己调用自己,例如斐波那契数列就是可以用简单递归来实现。 第一题 172. 阶乘后的零 https://leetcode.cn/problems/factorial-trailing-zeroes/description/ 这一题纯粹考数学推理能力,我这种菜鸡看了好久都没有懂。 大概是这样的思路&#x…...

Prime 1.0
信息收集 存活主机探测 arp-scan -l 或者利用nmap nmap -sT --min-rate 10000 192.168.217.133 -oA ./hosts 可以看到存活主机IP地址为:192.168.217.134 端口探测 nmap -sT -p- 192.168.217.134 -oA ./ports UDP端口探测 详细服务等信息探测 开放端口22&#x…...
Java 如何正确比较两个浮点数
看下面这段代码,将 d1 和 d2 两个浮点数进行比较,输出的结果会是什么? double d1 .1 * 3; double d2 .3; System.out.println(d1 d2);按照正常逻辑来看,d1 经过计算之后的结果应该是 0.3,最后打印的结果应该是 tru…...

Qt 如何操作SQLite3数据库?数据库创建和表格的增删改查?
# 前言 项目源码下载 https://gitcode.com/m0_45463480/QSQLite3/tree/main # 第一步 项目配置 平台:windows10 Qt版本:Qt 5.14.2 在.pro添加 QT += sql 需要的头文件 #include <QSqlDatabase>#include <QSqlError>#include <QSqlQuery>#include &…...

【Hadoop】分布式文件系统 HDFS
目录 一、介绍二、HDFS设计原理2.1 HDFS 架构2.2 数据复制复制的实现原理 三、HDFS的特点四、图解HDFS存储原理1. 写过程2. 读过程3. HDFS故障类型和其检测方法故障类型和其检测方法读写故障的处理DataNode 故障处理副本布局策略 一、介绍 HDFS (Hadoop Distribute…...
【Python-随笔】使用Python实现屏幕截图
使用Python实现屏幕截图 环境配置 下载pyautogui包 pip install pyautogui -i https://pypi.tuna.tsinghua.edu.cn/simple/下载OpenCV包 pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple/下载PyQT5包 pip install PyQt5 -i https://pypi.tuna.tsi…...

Sun Apr 16 00:00:00 CST 2023格式转换
Date date new Date(); log.info("当前时间为:{}",date); //yyyy-MM-dd HH:mm:ss SimpleDateFormat sdf new SimpleDateFormat(DateUtils.YYYY_MM_DD_HH_MM_SS); String dateTime s…...
使用mongodb实现简单的读写操作
本文适合初学者,特别是刚刚安装了mongodb数据库的朋友,或在atlas刚拿到免费集群的朋友。 拿到数据库,心情很激动,手痒难耐。特别想向数据库插入几条数据库试试。即使是深夜完成了安装,也忍不住想去完成这些操作。看到…...
C语言实现Cohen_Sutherland算法
前提简要: 算法简介: 编码算法是最早、最流行的线段裁剪算法,该算法采用区域检验的方法,能够快速有效地判断一条线段与裁剪窗口的位置关系,对完全接受或完全舍弃的线段无需求交,即可直接识别。 算法思想&…...

MySQL进阶_EXPLAIN重点字段解析
文章目录 第一节.准备1.1 版本信息1.2 准备 第二节.type2.1 system2.2 const2.3 eq_ref2.4 ref2.5 ref_or_null2.6 index_merge2.7 unique_subquery2.8 range2.9 index2.10 all 第三节. Extra3.1 No tables used3.2 No tables used3.3 Using where3.4 No matching min/max row3…...

视图层与模板层
视图层 1 视图函数 一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . . 是…...
MySQL数据库——触发器-案例(Insert类型、Update类型和Delete类型)
目录 表结构准备 插入数据触发器 代码 测试 修改数据触发器 代码 测试 删除数据触发器 代码 测试 通过触发器记录 tb_user 表的数据变更日志,将变更日志插入到日志表user_logs中,包含增加,修改,删除。 表结构准备 根据…...
快速创建桌面端(electron-egg)
介绍 | electron-egg electron-egg: 一个入门简单、跨平台、企业级桌面软件开发框架。 electron-egg是一个基于Electron和Egg.js的框架,可以用于快速构建跨平台的桌面应用程序。 1.兼容平台:electron-egg可以在Windows、MacOS和Linux等多个平台上运行…...

docker配置redis插件
docker配置redis插件 运行容器redis_6390 docker run -it \ --name redis_6390 \ --privileged \ -p 6390:6379 \ --network wn_docker_net \ --ip 172.18.12.19 \ --sysctl net.core.somaxconn1024 \ -e TIME_ZONE"Asia/Shanghai" -e TZ"Asia/Shanghai"…...

前端入口教程_web01
web标准 记得看! html:表示整个页面 head: titile: body: 常用标签 1.标题标签 2.段落标签 3.换行标签 4.文本格式化标签 5. 和 标签 6.图像标签 相对路径–用来插自己本地的图片 #### 绝对路径–用来插网上找的图…...

Win7 SP1 x64 Google Chrome 字体模糊
1 打开 Google Chrome ,地址栏输入 chrome://version/ ,字体模糊。 2 Microsoft Update Catalog 搜索更新 kb2670838,下载,安装,重启电脑。 3 打开 Google Chrome,地址栏输入 chrome://version/ ࿰…...

read()之后操作系统都干了什么
首先说明三个参数 file文件 buff从内存中开辟一段缓冲区用来接收读取的数据 size表示这个缓冲区的大小 有关file的参数: 状态:被打开 被关闭权限:可读可写最重要的是inode: 他包含了 文件的元数据(比如文件大小 文件类型 文件在访问前需要加…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...

android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...
【WebSocket】SpringBoot项目中使用WebSocket
1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖,添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...
Spring Boot + MyBatis 集成支付宝支付流程
Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例(电脑网站支付) 1. 添加依赖 <!…...