当前位置: 首页 > 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 消息队列服务来解决…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

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

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...