当前位置: 首页 > news >正文

初识--树(1)

下面就是这篇博客要讲的内容

    • 二叉树
  1. 树概念及结构
  2. 二叉树的概念及结构
  3. 二叉树的实现
  4. 堆的概念及运用

这篇博客主要以二叉树为主要内容。

1、树的概念及结构

1.1树的概念:

树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。

其中有三个注意的点:
(1)树有一个特殊的结点,称为根结点,根结点没有前驱结点
(2)除根结点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……、Tm,其中每一个集合Ti(1<= i<= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继因此,树是递归定义的。
(3)树形结构中,子树之间不能有交集,否则就不是树形结构
在这里插入图片描述
在这里插入图片描述
在第一个图中A节点就是我们的根节点。

1.2树的基本概念
在这里插入图片描述

(1)结点的度:一个结点含有的子树的个数称为该结点的度; 如上图:A的为6
(2)叶结点或终端结点:度为0的结点称为叶结点; 如上图:B、C、H、I…等结点为叶结点
(3)非终端结点或分支结点:度不为0的结点; 如上图:D、E、F、G…等结点为分支结点
(4)双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点; 如上图:A是B的父结点
(5)孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点; 如上图:B是A的孩子结点
(6)兄弟结点:具有相同父结点的结点互称为兄弟结点; 如上图:B、C是兄弟结点
(7)树的度:一棵树中,最大的结点的度称为树的度; 如上图:树的度为6
(8)结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推;
(9)树的高度或深度:树中结点的最大层次; 如上图:树的高度为4
(10)堂兄弟结点:双亲在同一层的结点互为堂兄弟;如上图:H、I互为兄弟结点
(11)结点的祖先:从根到该结点所经分支上的所有结点;如上图:A是所有结点的祖先
(12)子孙:以某结点为根的子树中任一结点都称为该结点的子孙。如上图:所有结点都是A的子孙

森林:由m(m>0)棵互不相交的树的集合称为森林;

1.3树的表示

这里就简单的了解其中最常用的孩子兄弟表示法——左孩子右兄弟。

typedef int DataType;
struct Node
{struct Node* firstChild1;// 第一个孩子结点struct Node* pNextBrother;// 指向其下一个兄弟结点DataType data;// 结点中的数据域
};

这就是我们树中的一个节点。
在这里插入图片描述
表现形式如上图。
这种方式来表示树非常的牛!大家可以试想如果我们不用这种方式我们怎样来表示我们的树——
树的分支数我们知道吗?那我们怎样定义我们的分支呢?那就只有顺序表,那顺序表开多大的空间?那样会非常的麻烦,而且会浪费我们的空间,而上图的方式完美解决了我们的问题。

2、二叉树的概念及结构

2.1 二叉树的概念
在这里插入图片描述
形如上图每个节点都最多只有两个分支的数就为我们的二叉树。

2.2 特殊的二叉树

  1. 满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。
  2. 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。
    在这里插入图片描述

2.3 二叉树的性质(非常重要,尽量自己尝试着去推导)

1、若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有(2^(i-1))个结点。
2、若规定根结点的层数为1,则深度为h的二叉树的最大结点数是2^h-1。
3、对任何一棵二叉树, 如果度为0其叶结点个数为n0 , 度为2的分支结点个数为n2 ,则有 n0= n2+1。
4、若规定根结点的层数为1,具有n个结点的满二叉树的深度,h=log(n+1)。(log以2为底)
5、对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有结点从0开始编号,则对于序号为i的结点有:

  1. 若i>0,i位置结点的双亲序号:(i-1)/2;i=0,i为根结点编号,无双亲结点
  2. 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
  3. 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子
    这三个推论在堆的实现、堆排序中使用,所以也希望大家能记住。
    由于篇幅原因我这里就不再给大家一步一步推了。

2.4 二叉树的存储

二叉树一般可以使用两种结构存储,一种顺序结构,一种链式结构。
(1)顺序结构

顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储,二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。
在这里插入图片描述
顺序结构有什么好处呢?
可以用下标来表示父子关系
在这里插入图片描述
(2)链式结构

二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。链式结构又分为二叉链和三叉链,当前我们学习中一般都是二叉链。

typedef int BTDataType;
// 二叉链
struct BinaryTreeNode
{
struct BinTreeNode* left;
// 指向当前结点左孩子
struct BinTreeNode* right; // 指向当前结点右孩子
BTDataType data;
// 当前结点值域
}

这篇博客先了解我们的链式存储,在下一篇我们就介绍顺序存储–堆。

三、二叉树链式结构的实现

3.1 二叉树的遍历(前序、中序以及后序遍历)

学习二叉树结构,最简单的方式就是遍历。所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的结点进行相应的操作,并且每个结点只操作一次。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。
在这里插入图片描述

按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历:

  1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
  2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
  3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。
    在这里插入图片描述

这里我画出来前序和中序,大家自己来画一下后序遍历,这一块可以为我们后面要学的搜索二叉树打下基础,这一块也是必须要掌握的。

遍历代码部分:

这里我们还没有学会创建我们的树,那么我们就用笨办法,手动去构建我们的树
(1)、首先我们要先确定树的形状,我这里的是自己随便画的大家可以自己来构建自己想要的树:
在这里插入图片描述
(2)代码构建:

typedef struct TreeNode
{int val;struct TreeNode* left;struct TreeNode* right;
}TreeNode;//二叉树的节点TreeNode* creatTree()
{TreeNode* node1 = (TreeNode*)malloc(sizeof(TreeNode));node1->val = 1;node1->left = node1->right = NULL;TreeNode* node2 = (TreeNode*)malloc(sizeof(TreeNode));node2->val = 2;node2->left = node2->right = NULL;TreeNode* node3 = (TreeNode*)malloc(sizeof(TreeNode));node3->val = 3;node3->left = node3->right = NULL;TreeNode* node4 = (TreeNode*)malloc(sizeof(TreeNode));node4->val = 4;node4->left = node4->right = NULL;TreeNode* node5 = (TreeNode*)malloc(sizeof(TreeNode));node5->val = 5;node5->left = node5->right = NULL;TreeNode* node6 = (TreeNode*)malloc(sizeof(TreeNode));node6->val = 6;node6->left = node6->right = NULL;TreeNode* node7 = (TreeNode*)malloc(sizeof(TreeNode));node7->val = 7;node7->left = node7->right = NULL;//创建我们的二叉树节点node1->left = node2;		node1->right = node3;node2->left = node4;		node2->right = node5;node5->right = node7;		node3->right = node6;//链接我们的树return node1;//返回树的根节点
}

(3)、遍历我们的二叉树:

void preOrder(TreeNode* root)
{if (root == NULL)return;printf("%d ", root->val);preOrder(root->left);preOrder(root->right);
}
int main()
{TreeNode* root = creatTree();preOrder(root);//前序遍历return 0;
}
void inOrder(TreeNode* root)//中序遍历
{if (root == NULL)return;inOrder(root->left);printf("%d ", root->val);inOrder(root->right);
}

大家可以看到代码部分非常的简单,但大家一定要明白它是怎样执行的。

3.2 层序遍历
层序遍历:除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根结点所在层数为1,层序遍历就是从所在二叉树的根结点出发,首先访问第一层的树根结点,然后从左到右访问第2层上的结点,接着是第三层的结点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
在这里插入图片描述
层序遍历就是一层一层访问,这里只是简单的介绍,这一块我们后面才学。

四、我们学完二叉树要解决的问题

4.1 二叉树的节点个数问题

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

关于这块的问题我们采用分置的思想。
节点个数:
1、根为空–0,
2、不为空–左子树+右子树+1。
这一块对于初学者确实非常的有难度,前期我们甚至可以将代码背下来。
大家需要在不断刷题后来慢慢体会。

4.2 二叉树的叶子节点个数问题

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

叶子节点特征:左右子树为空。
叶子:
1、根为空–0,
2、不为空–如果左子树右子树为空,就返回1。

4.3 二叉树的高度问题

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

高度:
1、根为空–0,
2、不为空–左子树与右子树中大的+1;

当然还有以下问题,大家可以自己尝试去解决,大家可以自己尝试去锻炼自己分置的思想。

1、单值二叉树。
2、 检查两颗树是否相同。
3、另一颗树的子树。
4、对称二叉树。
5、二叉树的构建与销毁。

总的来说这一部分还是非常的有难度,希望大家不要放弃,通过刷题去增强自己的信心。

相关文章:

初识--树(1)

下面就是这篇博客要讲的内容 树 二叉树堆 树概念及结构二叉树的概念及结构二叉树的实现堆的概念及运用 这篇博客主要以二叉树为主要内容。 1、树的概念及结构 1.1树的概念&#xff1a; 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限…...

渗透测试实战-菠菜站渗透测试(Nacos反序列化漏洞利用)

免责声明&#xff1a;文章来源于真实渗透测试&#xff0c;已获得授权&#xff0c;且关键信息已经打码处理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本…...

Pytest框架直接右键运行 testcase.py,不执行最外层conftest

随笔记录 目录 1. 背景介绍 2. workaround method 2.1 通过命令行执行 某个测试用例 1. 背景介绍 Pytest 框架结构如下&#xff1a; TestCases:conftest.pyInstanta: conftest.pytest_instanta_tcpdump_pack_len.py# 当直接右键直接 运行 test_instanta_tcpdump_pack_l…...

Cxx primer-chap15-Object-Oriented Programming

面向对象编程的三个基本概念&#xff1a;数据抽象、继承和动态绑定&#xff08;多态&#xff09;&#xff1a;基类应该提供一些类型无关的成员函数定义&#xff0c;将与类相关的函数留给不同的派生类定义&#xff1a;&#xff0c;派生类是通过类派生列表(class derivation list…...

当黑神话遇上AI:悟空背后的策划逆袭战

声明&#xff1a;此篇为 ai123.cn 原创文章&#xff0c;转载请标明出处链接&#xff1a;https://ai123.cn/2192.html 哈喽&#xff0c;亲爱的游戏迷&#xff0c;随着《黑神话&#xff1a;悟空》的上线&#xff0c;大家都在忙着“直面天命”了吧&#xff1f;今天我想和大家分享最…...

外呼触发通知发送闪信(mod_cti基于FreeSWITCH)

文章目录 前言联系我们手动外呼配置方法例子一&#xff1a;接收到180或183时触发闪信发送例子二&#xff1a;挂断后触发闪信发送 自动外呼配置方法例子&#xff1a;接收到180或183时触发闪信发送 前言 在呼叫中心中间件中&#xff0c;自动外呼触发闪信发送&#xff0c;我们可以…...

8.Java基础概念-方法

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 Facts speak louder than words&#xff01; 什么是方法 方法是程序…...

360安全浏览器如何彻底卸载

360安全浏览器是一款广泛使用的网络浏览工具&#xff0c;然而由于各种原因&#xff0c;用户可能需要将其从计算机中彻底移除。下面小编就给大家分享几种彻底卸载360安全浏览器的方法&#xff0c;避免留下影响系统性能的残留信息。&#xff08;本文由https://chrome.cmrrs.com/站…...

构建基于LLM的应用程序——使用LLM的搜索和推荐引擎

在上一章中&#xff0c;我们介绍了构建对话应用程序的核心步骤。我们从一个基础的聊天机器人开始&#xff0c;然后逐步添加了更复杂的组件&#xff0c;例如记忆、非参数化知识和外部工具。借助LangChain的预构建组件以及Streamlit的UI渲染&#xff0c;这一切都变得相对简单。尽…...

Unity3D 模型碰撞检测问题详解

前言 在Unity3D游戏开发中&#xff0c;模型碰撞检测是至关重要的一环&#xff0c;它负责处理物体之间的交互、触发事件以及物理效果的实现。通过精确的碰撞检测&#xff0c;游戏世界得以呈现出更为真实和动态的交互体验。本文将详细介绍Unity3D中的碰撞检测原理、技术实现以及…...

springcloud集成seata实现分布式事务

Seata 是一款开源的分布式事务解决方案&#xff0c;致力于在微服务架构下提供高性能和简单易用的分布式事务服务。 官网&#xff1a;Apache Seata 文章目录 一、部署1.下载2.修改配置&#xff0c;nacos作注册中心&#xff0c;db存储 二、集成到springcloud项目1.引入依赖2.修改…...

[Leetcode 61][Medium]-旋转链表

目录 一、题目描述 二、整体思路 三、代码 一、题目描述 原题链接 二、整体思路 首先发现这样的规律&#xff1a;当k大于等于链表中节点总数n时&#xff0c;会发现此时旋转后的链表和kk%n时的旋转后的链表一样。同时对于特殊情况n0和n1时&#xff0c;无论k的值为多少都可以…...

高效分页策略:掌握 LIMIT 语句的正确使用方法与最佳实践

本文主要介绍limit 分页的弊端及线上应该怎么用 LIMIT M,N 平时经常见到使用 <limit m,n> 合适的 order by 来实现分页查询&#xff0c;这样做到底性能如何呢&#xff1f; 先来简单分析下&#xff0c;然后再实际验证一下。 无索引条件下&#xff0c;需要做大量的文件排…...

拼图游戏02

文章目录 概要整体架构流程代码过程小结 概要 现在需要将图片添加界面中 关键点在于它如何动态地根据游戏状态更新用户界面。它使用了Swing的布局管理器来定位组件&#xff0c;并且通过ImageIcon和JLabel来显示图像。注意&#xff0c;路径字符串中的反斜杠在Java中是转义字符…...

在本地进行Django支付宝扫码支付-当面付开发

这几天涉及到一个个人项目的支付开发场景&#xff0c;正好完成之后&#xff0c;做一下开发记录&#xff0c;给有需要的朋友做一下参考 涉及安装Python环境请参考我专栏中的历史文章&#xff0c;这里不再重复说明 环境&#xff1a; Python3.11 使用Django框架 因本次代码为沙…...

redis-RedisTemplate.opsForGeo 的geo地理位置相关的方法演示

主要方法&#xff1a;add : 添加一个地理位置distance: 计算两个元素之间的距离hash&#xff1a; 获取元素经纬度坐标经过geohash算法生成的base32编码值position: 获取集合中任意元素的经纬度坐标&#xff0c;可以一次获取多个radius&#xff1a;查询某个坐标或某个成员&#…...

做短视频矩阵要十几人团队吗?云微客助阵,一人即可

现在市面上主流的新媒体平台都进军了短视频赛道&#xff0c;对于众多企业和个人来说&#xff0c;短视频矩阵更是成为了提升影响力和拓展业务的关键。企业或个人可以根据自身产品特点和目标用户群体&#xff0c;构建账号矩阵&#xff0c;在多平台上建立账号矩阵&#xff0c;还可…...

常用语音识别开源工具的对比与实践

常用语音识别开源工具的对比 一.工具概述 1. WeNet 设计目标&#xff1a;WeNet 的设计主要聚焦于端到端&#xff08;E2E&#xff09;语音识别&#xff0c;特别是在流式识别方面的优化。其目标是提供一个可以在实际应用中达到低延迟和高精度的系统。模型架构&#xff1a; Con…...

Fortify代码安全测试工具在静态应用安全测试(SAST)方面针对典型问题的改进

Fortify代码安全测试工具作为行业内资深的老牌软件安全测试工具&#xff0c;可以同时支持静态代码扫描和动态代码扫描&#xff0c;本文我们讲述的主要是在静态代码扫描领域Fortify所面临的问题&#xff0c;以及最新的改进。 在应用安全领域&#xff0c;特别是静态应用安全测试&…...

AWS 消息队列服务 SQS

AWS 消息队列服务 SQS 引言什么是 SQSSQS 访问策略 Access Policy示例&#xff1a;如何为 DataLake Subscription 配置 SQS 引言 应用系统需要处理海量数据&#xff0c;数据发送方和数据消费方是通过什么方式来无缝集成消费数据的&#xff0c;AWS 提供 SQS 消息队列服务来解决…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要&#xff1a; 近期&#xff0c;在使用较新版本的OpenSSH客户端连接老旧SSH服务器时&#xff0c;会遇到 "no matching key exchange method found"​, "n…...

算法刷题-回溯

今天给大家分享的还是一道关于dfs回溯的问题&#xff0c;对于这类问题大家还是要多刷和总结&#xff0c;总体难度还是偏大。 对于回溯问题有几个关键点&#xff1a; 1.首先对于这类回溯可以节点可以随机选择的问题&#xff0c;要做mian函数中循环调用dfs&#xff08;i&#x…...

基于Uniapp的HarmonyOS 5.0体育应用开发攻略

一、技术架构设计 1.混合开发框架选型 &#xff08;1&#xff09;使用Uniapp 3.8版本支持ArkTS编译 &#xff08;2&#xff09;通过uni-harmony插件调用原生能力 &#xff08;3&#xff09;分层架构设计&#xff1a; graph TDA[UI层] -->|Vue语法| B(Uniapp框架)B --&g…...

Element-Plus:popconfirm与tooltip一起使用不生效?

你们好&#xff0c;我是金金金。 场景 我正在使用Element-plus组件库当中的el-popconfirm和el-tooltip&#xff0c;产品要求是两个需要结合一起使用&#xff0c;也就是鼠标悬浮上去有提示文字&#xff0c;并且点击之后需要出现气泡确认框 代码 <el-popconfirm title"是…...

react-pdf(pdfjs-dist)如何兼容老浏览器(chrome 49)

之前都是使用react-pdf来渲染pdf文件&#xff0c;这次有个需求是要兼容xp环境&#xff0c;xp上chrome最高支持到49&#xff0c;虽然说iframe或者embed都可以实现预览pdf&#xff0c;但为了后续的定制化需求&#xff0c;还是需要使用js库来渲染。 chrome 49测试环境 能用的测试…...

JUC并发编程(二)Monitor/自旋/轻量级/锁膨胀/wait/notify/锁消除

目录 一 基础 1 概念 2 卖票问题 3 转账问题 二 锁机制与优化策略 0 Monitor 1 轻量级锁 2 锁膨胀 3 自旋 4 偏向锁 5 锁消除 6 wait /notify 7 sleep与wait的对比 8 join原理 一 基础 1 概念 临界区 一段代码块内如果存在对共享资源的多线程读写操作&#xf…...