数据结构:二叉树概念篇(算法基础)

news2024/11/6 7:21:12

目录

一.有向树的图论基础

1.有向树的相关基本概念

有向树的基本定义:

有向树的结点的度:

有向树的度:

有向树的根结点,分枝结点,叶结点: 

树的子树:

树结点的层次:

树的高度:

2.一个基本的数学结论

3.有序有向树

二.数据结构中树的顺序存储结构与链式存储结构

1.数据结构的物理结构与逻辑结构

2.物理结构为顺序表(数组)的树形数据结构

3. 物理结构为链表的树形数据结构

三.二叉树

1.二叉树基本概念 

2.两个重要的特殊二叉树

3. 关于二叉树的一些常用数学结论

(1).第一组结论 

(2).第二组结论(数组实现二叉树的算法基础)


一.有向树的图论基础

基本引理:如果图G(结点数大于等于2)中不存在回路,则至少有一个结点的度为1 

本篇所讨论的树都是有向树 

1.有向树的相关基本概念

  • 有向树的基本定义:

设T是由有限个结点构成有向简单连通图,且T的无向底图不存在任何回路,则称T为有向树:

  • 有向树的结点的度:

 结点的入度:现有树结点A,以A为终点的有向边的条数称为结点A的入度:

结点的出度: 现有树结点A,以A为起点的有向边的条数称为结点A的出度:

以结点A为终点的有向边的另一端的结点称为A的父结点(parent)

以结点A为起点的有向边的另一端的结点称为A的孩子结点(child)

  •  有向树的度:

有向树的度 = 该树所有结点的出度中的最大值:

  • 有向树的根结点,分枝结点,叶结点: 

  1. 根结点的入度为0
  2. 叶结点的出度为0
  3. 其余入度和出度均不为0的结点称为树的分枝结点  
  •  树的子树:

将一个有向树T的根结点去掉,该树则会被分成若干个互不连通的子树,如图:

上图中T的子树t1,t2,t3都可以再以相同的方式被划分成更小的子树直到树图被划分为若干树叶.

注意:在仅有一个根结点的树形结构中子树之间没有通路(不然图中会出现回路)

  • 树结点的层次:

从根结点开始算起沿着有向边进行遍历,根结点某一个特定结点所遍历的结点个数称为某特定结点的层次

  1.  层次相同父结点相同的结点互为兄弟结点(比如上图中的E和F)
  2.  层次相同父结点不同的结点互为堂兄弟结点(比如上图中的F和G)
  • 树的高度:

树的所有结点的层次中的最大值称为该树的高度:比如上图中的树的高度为4

2.一个基本的数学结论

  • 关于树的一个基本命题:若树有n个结点,m条有向边,则m=n-1;

该性质可以通过数学归纳法进行证明:

  1. 显然n=1时,则m=0,m=n-1成立;
  2. 假设n=k(k>=1)时命题成立,任意具有k个结点的树都有k-1条边
  3. 设树G有n=k+1个结点时(k>=1)边数为m。 由于G中没有回路,根据基本引理G中必然存在度(出度+入度)为1的结点,设这个结点为u。 从G中删去结点u(相当于同时删去了一条边和一个结点)根据定义G仍是树,(根据n=k时的假设2)G有k个节点,故有k-1条边,从而m=(k-1)+1=k=n-1(将u结点加回来,边数相应地增加1)。(即若n=k时命题成立则n=k+1时命题也成立,那么从n=1开始构建任意结点数量的树也满足m=n-1)

该证明过程充分体现了树在逻辑上是递推构建起来的图:

分析树的构建图解可知:

  • 若构建仅有一个根结点的有向树,则该有向树的每棵子树的根结点有且只有一个父节点可以有0个或多个孩子结点.
  • 同时易知:在仅有一个根结点的树形结构中,一棵树的子树之间不存在通路

3.有序有向树

满树的概念:

  • 设(单个根结点)树T的高度为h(h>1),度为k(k>=1)(树的结点个数大于1)
  • 树T对应的满树的概念:高度为h根结点每一个分枝结点的出度都为k的树
  • 有序有向树的每一个结点都有自己固定的编号

 有序有向树各结点的编号规则:

  1. 设现在有一颗高度为h,度为k的(单个根结点的)树T(h>1,,k>=1)
  2. 先作出树T对应的满树
  3. 树T对应的满树的各结点按照从低层到高层,从左往右的次序进行编号
  4. 根据满树各结点的编号对树T相应位置的结点进行编号

比如:

二.数据结构中树的顺序存储结构与链式存储结构

如果将树的结点看成是一个个内存区块,结点间的有向线段看成是各内存区块之间的关联(这种关联可能是通过指针或者数组下标关系建立起来的),这种在内存中形成的数据结构就是树形数据结构

1.数据结构的物理结构与逻辑结构

  • 数据结构的物理结构指的是该数据结构在内存中的真实分布模型
  • 数据结构的逻辑结构指的是数据结构的抽象分析模型

数据结构的类型主要取决于其逻辑结构,其逻辑结构和物理结构之间是通过逻辑映射来建立联系的

2.物理结构为顺序表(数组)的树形数据结构

  • 现有一颗度数为2的非满树T
  • 我们先将一个树T对应的满树的各个结点按照从低层次到高层次,从左往右的顺序进行编号:
  •  由此我们可以得到树T各个结点的编号:
  • 根据树T各结点的编号我们就可以将这棵树映射到一个数组上去:
  • 通过结点编号与数组下标的绝对映射,我们便可以通过数组来实现树形数据结构(有序有向树) 
  • 顺序表实现的树中,非常经典的例子就是堆(大小根堆)

3. 物理结构为链表的树形数据结构

我们可以定义一个结构体类型:

typedef int DataType;
struct Node
{
    struct Node* _firstChild1;  // 第一个孩子结点
    struct Node* _pNextBrother; // 指向其下一个兄弟结点
    DataType _data;             // 结点中的数据域
};
  • _firstChild1用于指向该结点的第一个孩子结点(编号意义上的第一个(位于左侧))
  • _pNextBrother用于指向与该结点位于相同层次具有相同父结点兄弟结点

现在有一颗树:

我们用链式存储结构来实现它:

通过_firstChild1指针我们可以实现树的深度遍历

通过_pNextBrother指针我们可以实现树的广度遍历

三.二叉树

1.二叉树基本概念 

一棵二叉树是结点的一个有限集合:

  1. 二叉树的度为2,即不存在出度大于2的结点
  2. 二叉树结点的孩子结点有左右之分(左右孩子),次序不能颠倒,二叉树是有序有向树(各结点都有自己对应的固定编号)

对于任意的二叉树都是由以下几种情况复合而成

2.两个重要的特殊二叉树

  • 满二叉树:一个二叉树,如果根结点和每一个分枝结点的出度都为2,则这个二叉树就是满二叉树。从结点总个数角度分析:如果一个二叉树的层数为K,且结点总数是2^k - 1(等比数列求和),则它就是满二叉树.
  • 完全二叉树:完全二叉树是效率很高的数据结构;
    对于高度为K的,有n个结点的二叉树,当且仅当其所有结点编号为1到n连续排列时称之为完全二叉树。(基于完全二叉树的结点编号特点,用数组来实现完全二叉树,内存利用率较高)

完全二叉树有一个特点:

若完全二叉树的高度为k(k>1),则其前k-1层所有结点构成的子结构是一颗满树

  •  用数组实现完全二叉树非完全二叉树的对比:可见完全二叉树的优势所在
  •  数据结构堆就是用顺序表(数组)实现的完全二叉树(堆是堆排序算法的结构基础)

3. 关于二叉树的一些常用数学结论

接下来我们给出两组在后续的算法学习中会用到的关于二叉树的数学结论

(1).第一组结论 

  • 对任何一棵二叉树, 如果出度为0其叶结点个数为N0, 出度为2的分支结点个数为N2(包括根) ,则有 N0= N2+1

证明:

设该二叉树出度为1的分枝结点个数为N1;

该二叉树中的总边数为: 2*N2 + N1;

二叉树中的总结点个数为: N0 + N1 + N2

根据第一章第2小节的基本数学结论有:2*N2 + N1 = N0 + N1 + N2 -1(树的总边数 = 结点数-1)

化简可得:N0 = N2 +1;(即二叉树中,出度为0的树叶永远比出度为2的分枝结点(包括根)多一个)

(2).第二组结论(数组实现二叉树的算法基础)

  • 定理一:对于具有n个结点的完全二叉树,按照第一章第3节所述的编号规则将其各结点进行编号(根结点我们规定编为0号,则完全二叉树的各结点编号为0~n-1),则对于编号为child的结点有如下结论:若child>0,child编号结点的父结点编号parent = (child-1)/2;若child=0 ,该结点无父结点 

定理一证明图解:

  • 定理二:对于具有n个结点的完全二叉树,按照第一章第3节所述的编号规则将其各结点进行编号(根结点我们规定编为0号,则完全二叉树的各结点编号为0~n-1),则对于编号为parent的结点有如下结论:2*parent+1<n,则可得该结点的左孩子结点编号leftchild = 2*parent+1;若2*parent+1>=n,则该结点无左孩子(该结论是定理一的逆定理)
  • 定理三:对于具有n个结点的完全二叉树,按照第一章第3节所述的编号规则将其各结点进行编号(根结点我们规定编为0号,则完全二叉树的各结点编号为0~n-1),则对于编号为parent的结点有如下结论:若2*parent+2<n,则可得该结点的右孩子结点编号rightchild = 2*parent+2;若2*parent+2>=n该结点无右孩子(该结论是定理一的逆定理)

定理二和三的证明分析图解:

有了该组定理我们就可以通过一个父结点的编号找到其左右孩子结点的编号,反过来也可以通过孩子结点的编号找到其父结点的编号(该组定理为数组实现二叉树奠定了算法基础)

  • 该组定理在后续堆的实现中的堆元素插入删除接口元素上下调整算法中会用到

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

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

相关文章

【华为OD机试模拟题】用 C++ 实现 - 星际篮球争霸赛(2023.Q1)

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…

【log】操作类日志处理 与 报错类日志处理logback

文章目录一、操作类日志处理【环绕增强】aop环绕增强导包第一步&#xff1a;自定义注解interface第二步&#xff1a;在Controller写一个测试的方法&#xff1a;第三步&#xff1a;编写LogAspect增强类与增强方法日志写入数据库&#xff08;使用mybatis&#xff09;第一步&#…

C/C++每日一练(20230225)

目录 1. 工龄问题求解 ★ 2. 字符图形输出 ★★ 3. LRU 缓存机制 ★★★ 1. 工龄问题求解 给定公司N名员工的工龄&#xff0c;要求按工龄增序输出每个工龄段有多少员工。输入首先给出正整数N&#xff0c;即员工总人数&#xff1b; 随后给出N个整数&#xff0c;即每个员工…

图像分割评价指标:Dice和MIoU

目录Dice理论代码MIou理论查准率 precison查全率 recallMIoU 平均交并比代码高效的矩阵运算低效的好理解的计算混淆矩阵Dice和MIoU两者的关系参考链接Dice 理论 Dice用来衡量预测结果pred和标签label的相似度&#xff0c;公式如下图所示&#xff0c;即两个集合的交集/并集。 …

Java-多线程-增强篇-锁强化第3篇

Java集合框架中的锁 今天我们继续来学习锁 字符串操作中的锁 String是线程安全的&#xff0c;因为使用final修饰Stringbuilder 是线程不安全的&#xff0c;其方法没有使用synchronized修饰StringBuffer 是线程安全的&#xff0c;其方法使用synchronized修饰 List集合中的锁 …

【人工智能 AI】可以从 RPA 中受益的 10 个行业 10 Industries That Can Benefit From RPA

目录 RPA技术介绍 Which industries can use robotic process automation?哪些行业可以使用机器人过程自动化? Robotic process automation in the retail industry零售业中的机器人过程自动化 Robotic process automation in the construction industry建筑行业的机器人…

RebbitMQ 消息队列(高级应用)

RabbitMQ 高级特性 消息可靠性投递&#xff0c;consumer ACK&#xff0c;消费端限流&#xff0c;TTL&#xff0c;死信队列&#xff0c;延迟队列&#xff0c;日志与监控&#xff0c;消息可靠性与追踪&#xff0c;管理 RabbitMQ 应用问题 消息可靠性保障&#xff0c;消息幂等性…

JavaScript 基础【快速掌握知识点】

目录 为什么要学JavaScript? 什么是JavaScript 特点&#xff1a; 组成&#xff1a; JavaScript的基本结构 基本结构 内部引用 外部引用 console对象进行输出 JavaScript核心语法 1、变量声明 2、数据类型 3、运算符 4、条件语句 5、循环语句 6、数组 7…

【shell】for while 循环的例子,快速了解

for 循环读一个文件的每一行 for i in cat temp.list;do echo $i;done for ip in $(cat ip.list);do ping -c 2 $ip;done循环打印数字 for a in {1…5};do echo $a;done for a in {1…5…2};do echo $a;done #等差 for a in $(seq 1 5);do echo $a;done for a in $(seq 1 2 5)…

内网穿透常用方法系列总结

前言在内网渗透时&#xff0c;一个WebShell或CobaltStrike、Metasploit上线等&#xff0c;只是开端&#xff0c;更多是要内网横向移动&#xff0c;扩大战果&#xff0c;打到核心区域。但后渗透的前提是需要搭建一条通向内网的“专属通道”&#xff0c;才能进一步攻击。可实战中…

【华为OD机试模拟题】用 C++ 实现 - 找出重复代码(2023.Q1)

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…

C语言static关键字

目录static修饰局部变量static修饰全局变量static修饰函数static是C语言的关键字&#xff0c;它有静态的意思static的三种用法&#xff1a;修饰局部变量修饰全局变量修饰函数 static修饰局部变量 我们先看一个程序&#xff1a; void print() {int a 0;a;printf("%d\n&…

【华为OD机试模拟题】用 C++ 实现 - 数组组成的最小数字(2023.Q1)

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…

更改tomcat访问端口()

1Centos7开启端口 查看防火墙状态命令&#xff1a; systemctl status firewalld 启动防火墙命令&#xff1a; systemctl start firewalld 关闭防火墙命令&#xff1a; systemctl stop firewalld 开放端口命令&#xff1a; firewall-cmd --zonepublic --add-port5011/tcp --pe…

23、高自由度下的E类波形理论计算(附Matlab代码)

23、高自由度下的E类波形理论计算&#xff08;附Matlab代码&#xff09; 0、代码 任意占空比、电压导数条件下的E类波形与阻抗条件计算Matlab 注意修改路径&#xff0c;我这边是&#xff1a;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#…

自适应池化、最大值池化和均值池化效率的比较分析

1 问题我们在深度学习的过程中&#xff0c;我们学到了自适应池化、最大值池化和均值池化。那么&#xff0c;我们想要探究一下自适应池化、最大值池化和均值池化效率&#xff0c;哪一个更高&#xff1f;2 方法在之前的学习中&#xff0c;我们学到了自适应池化、最大值池化和均值…

c++11 标准模板(STL)(std::unordered_set)(八)

定义于头文件 <unordered_set> template< class Key, class Hash std::hash<Key>, class KeyEqual std::equal_to<Key>, class Allocator std::allocator<Key> > class unordered_set;(1)(C11 起)namespace pmr { templ…

【Rust 日报】2023-2-24 Dioxus 0.3 发布,巨大的更新

ascii-d - 画ASCII示意图的工具Rust写的画ASCII示意图的工具。支持各大平台。程序员的最爱啊。https://github.com/huytd/ascii-d/raw/master/_meta/toolbar-final.gifDioxus 0.3 发布&#xff0c;巨大的更新Dioxus 是新出的与 Yew 类似的 Rust Web 前端框架&#xff08;为什么…

【sciter】sciter数据可视化

一、柱状图 <div class="bar-chart item"></div> <!-- bar-chart --> <script type

【华为OD机试模拟题】用 C++ 实现 - 找单词(2023.Q1)

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…