【数据结构与算法理论知识点】 4、树和二叉树

news2024/9/20 10:43:41

4、树和二叉树

逻辑结构

在这里插入图片描述

4.1、树的定义和基本术语

树是n个结点的有限集

在这里插入图片描述

树的其他表示方式

在这里插入图片描述

基本术语

根——即根结点(没有前驱)

叶子——即终端结点(没有后继)

森林——指m棵不相交的树的集合(例如删除根节点A后的子树)

有序树——结点各子树从左至右有序,不能互换(左为第一)

无序树——结点各子树可互换位置

双亲——即上层的那个结点(直接前驱)

孩子——即下层结点的子树的根(直接后继)

兄弟——同一双亲下的同层结点(孩子之间互称兄弟)

堂兄弟——即双亲位于同一层的结点(但并非同一双亲——

祖先——即从根到该结点所经分支的所有结点

子孙——即该节点下层子树中的任一结点

结点——即树的数据元素

结点的度——结点挂接的子树数

结点的层次——从根到该结点的层数(根结点算第一层)

叶子结点——即度为0的结点

内结点——即度不为0的结点

树的度——所有结点度中的最大值

树的深度(或高度)——指所有结点中最大的层数

4.2、二叉树

普通树(多叉树)若不转化为二叉树,则运算很难实现

为何要重点研究每结点最多只有两个“叉”的树?

  • 二叉树的结构最简单,规律最强

  • 可以证明,所有树都能转为唯一对应的二叉树,不失一般性

二叉树的基本特点

  • 结点的度小于等于2
  • 有序树(子树有序,不能颠倒)

在这里插入图片描述

二叉树的性质

性质1:在二叉树的第i层上至多有2^i-1个结点

第i层上至少有1个结点

性质2:深度为k的二叉树至多有(2^k)-1个结点

深度为k时至少有k个结点

性质3:对于任何一棵二叉树,若2度的结点有n2个,则叶子树n0必定为n2+1(即n0=n2+1)
B = n − 1 B=n-1 B=n1

B = n 2 × 2 + n 1 × 1 B=n_2×2+n_1×1 B=n2×2+n1×1

n = n 2 × 2 + n 1 × 1 + 1 = n 2 + n 1 + n 0 n=n_2×2+n_1×1+1=n_2+n_1+n_0 n=n2×2+n1×1+1=n2+n1+n0

特殊形态的二叉树

满二叉树:一棵深度为k且有(2^k)-1个结点的二叉树。(特点:每层都“充满”了结点)

在这里插入图片描述

完全二叉树:深度为k的,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对于

在这里插入图片描述

问题:一个有5000个结点的完全二叉树的叶结点个数是(2500)。

解:

设二叉树中度为0结点个数为n0,度为1的结点个数为n1,度为2的结点个数为n2
于是 n0 + n1 + n2 = 500,由二叉树性质n0 = n2 + 1,代入得到:2n2 + 1 + n1 = 5000
显然n1是奇数,考虑到完全二叉树中度为1结点个数最多为1,因此n1 = 1
因此n2 = 2499,n0 = 2500,只有左孩子的结点个数为1
考虑到完全二叉树中没有结点只有右孩子,因此只有右孩子的结点个数为0

**性质4:**具有n个结点的完全二叉树的深度必为[logn]+1

在这里插入图片描述

性质5: 对完全二叉树,若从上至下、从左至右编号,则编号为i 的结点,其左孩子编号必为2i,其右孩子编号必为2i+1;其双亲的编号必为i/2。

一个有3999个结点的最大堆对应的完全二叉树的最后一个内结点的编号是(1999)。
(奇数个节点的完全二叉树最后一个内节点的编号是度为2的个数)

二叉树的顺序存储

实现:按满二叉树的结点层次编号,依次存放二叉树中的数据元素。

在这里插入图片描述

在这里插入图片描述

特点:结点间关系蕴含在其存储位置中,浪费空间,适于存满二叉树和完全二叉树

二叉树的链式存储

在这里插入图片描述

二叉链表:只有左右孩子指针

在这里插入图片描述

typedef struct BiNode{
   TElemType   data;
   struct  BiNode   *lchild,*rchild; //左右孩子指针
}BiNode,*BiTree; 

在n个结点的二叉链表中,有n+1个空指针域

分析:必有2n个链域。除根结点外,每个结点有且仅有一个双亲,所以只会有n-1个结点的链域存放指针,指向非空孩子结点。

空指针数目=2n-(n-1)=n+1

三叉链表:有双亲和左右孩子指针

在这里插入图片描述

typedef struct TriTNode{
    TelemType data;
    struct TriTNode *lchild,*parent,*rchild;
}TriTNode,*TriTree;

4.3、遍历二叉树

遍历定义——指按某条搜索路线遍访每个结点且不重复(又称周游)。

遍历用途——它是树结构插入、删除、修改、查找和排序运算的前提,是二叉树一切运算的基础和核心

遍历规则

在这里插入图片描述

先左后右

DLR(先序) LDR(中序) LRD(后序)(√)

DRL RDL RLD(×)

在这里插入图片描述

用二叉树表示算术表达式

在这里插入图片描述

遍历的算法实现——先序遍历

若二叉树为空,则空操作
否则

访问根结点 (D)

先序遍历左子树 (L)

先序遍历右子树 ®

在这里插入图片描述

在这里插入图片描述

先序遍历序列:A B D C

遍历的算法实现--用递归形式格外简单!

先序遍历算法

Status PreOrderTraverse(BiTree T){
  if(T==NULL) return OK; //空二叉树
  else{    
     cout<<T->data; //访问根结点
     PreOrderTraverse(T->lchild); //递归遍历左子树
     PreOrderTraverse(T->rchild); //递归遍历右子树
    }
}

在这里插入图片描述

遍历的算法实现-中序遍历

若二叉树为空,则空操作
否则:

中序遍历左子树 (L)

访问根结点 (D)

中序遍历右子树 ®

在这里插入图片描述

在这里插入图片描述

中序遍历序列:B D A C

中序遍历算法

Status InOrderTraverse(BiTree T){
  if(T==NULL) return OK; //空二叉树
  else{    
     InOrderTraverse(T->lchild); //递归遍历左子树
  cout<<T->data; //访问根结点
     InOrderTraverse(T->rchild); //递归遍历右子树
    }
}

遍历的算法实现-后序遍历

若二叉树为空,则空操作
否则

后序遍历左子树 (L)

后序遍历右子树 ®

访问根结点 (D)

在这里插入图片描述

在这里插入图片描述

后序遍历序列: D B C A

Status PostOrderTraverse(BiTree T){
  if(T==NULL) return OK; //空二叉树
  else{    
     PostOrderTraverse(T->lchild); //递归遍历左子树
     PostOrderTraverse(T->rchild); //递归遍历右子树
     cout<<T->data; //访问根结点
    }
}

遍历算法的分析

在这里插入图片描述

如果去掉输出语句,从递归的角度看,三种算法是完全相同的,或说这三种算法的访问路径是相同的,只是访问结点的时机不同。

从虚线的出发点到终点的路径上,每个结点经过3次。

第1次经过时访问=先序遍历
第2次经过时访问=中序遍历
第3次经过时访问=后序遍历

时间效率:O(n) //每个结点只访问一次
空间效率:O(n) //栈占用的最大辅助空间

二叉树的建立

按先序遍历序列建立二叉树的二叉链表

例:已知先序序列为: A B C   D E  G   F   

在这里插入图片描述

常识:

  • 若二叉树中各结点的值均不相同,则:
    由二叉树的前序序列+中序序列,或由其后序序列+中序序列均能唯一地确定一棵二叉树,
    但由前序序列+后序序列却不一定能唯一地确定一棵二叉树。
  • 后序遍历,根节点必须在后序序列的尾部
  • 前序遍历,根节点必须在前序序列的头部

练习:

已知一棵二叉树的中序序列和后序序列分别是BDCEAFHG 和 DECBHGFA,请画出这棵二叉树。

①由后序遍历特征,根结点必在后序序列尾部(A);
②由中序遍历特征,根结点必在其中间,而且其左部必全部是左子树子孙(BDCE),其右部必全部是右子树子孙(FHG);
③继而,根据后序中的DECB子树可确定B为A的左孩子,根据HGF子串可确定F为A的右孩子;以此类推。

在这里插入图片描述

二叉树遍历算法的应用

  • 计算二叉树结点总数
  • 计算二叉树叶子总数
  • 计算二叉树高度

4.4、树和森林

树的存储结构
-双亲表示法
-孩子表示法
-双亲孩子表示法
-孩子兄弟表示法

树的存储结构-双亲表示法

在这里插入图片描述

树的存储结构-孩子表示法

在这里插入图片描述

在这里插入图片描述

树的存储结构-双亲孩子表示法

在这里插入图片描述

在这里插入图片描述

树的存储结构-孩子兄弟表示法

在这里插入图片描述

在这里插入图片描述

森林的存储结构
-双亲表示法
-孩子表示法
-孩子兄弟表示法

树、森林和二叉树的相互转换

在这里插入图片描述

树→二叉树

  • 加线:将兄弟结点用线相连
  • 抹线:保留双亲与最左边孩子的连线,去掉双亲和其他孩子的连线
  • 旋转:将经过加线和去线以后的结果,进行旋转处理得到转换后的二叉树

在这里插入图片描述

二叉树→树

  • 加线:将结点和其左孩子结点的右孩子以及右孩子的右孩子加线相连
  • 抹线:去掉结点和右孩子的连线
  • 旋转:将加线、去线后的结果,进行旋转处理,就得到转换后的树

在这里插入图片描述

森林→二叉树

  • 将每棵树分别转换成二叉树
  • 将每棵树的根结点用线相连
  • 以第一棵树根结点为二叉树的根,再以根结点为轴心,顺时针旋转,构成二叉树型结构

在这里插入图片描述

二叉树→森林

  • 抹线:将二叉树中根结点与其右孩子连线,及沿右分支搜索到的所有右孩子间连线
  • 全部抹掉,使之变成孤立的二叉树
  • 还原:将孤立的二叉树还原成树

在这里插入图片描述

树的遍历

按一定规律走遍树的各个顶点,且使每一顶点仅被访问一次,即找一个完整而有规律的走法,以得到树中所有结点的一个线性排列
遍历方法
先根(序)遍历:先访问树的根结点,然后依次先根遍历根的每棵子树
后根(序)遍历:先依次后根遍历每棵子树,然后访问根结点
按层次遍历:先访问第一层上的结点,然后依次遍历第二层,……第n层的结点

”树“非同二叉树它没有中序遍历

在这里插入图片描述

森林的遍历

  • 先序遍历
    • 访问森林中第一棵树的根结点
    • 先序遍历第一树中根结点的子树森林
    • 先序遍历除去第一棵树之后剩余的森林
  • 后序遍历
    • 后序遍历森林中第一棵树的根结点的子树森林
    • 访问第一棵树的根结点
    • 后序遍历除去第一棵树之后剩余的森林

在这里插入图片描述

4.5、二叉树的应用

在这里插入图片描述

4.5.1二叉排序树

二叉排序树或是空树,或是满足如下性质的二叉树:
(1)若其左子树非空,则左子树上所有结点的值均小于根结点的值;
(2)若其右子树非空,则右子树上所有结点的值均大于等于根结点的值;
(3)其左右子树本身又各是一棵二叉排序树

在这里插入图片描述

中序遍历二叉排序树后的结果有什么规律?

在这里插入图片描述

得到一个关键字的递增有序序列

二叉排序树的操作-查找

若查找的关键字等于根结点,成功
否则
 若小于根结点,查其左子树
 若大于根结点,查其右子树
在左右子树上的操作类似

在这里插入图片描述

算法描述

BSTree SearchBST(BSTree T, KeyType key) {
   if((!T) || key==T->data.key) return T;       	 
   else if (key<T->data.key)  return SearchBST(T->lchild,key);	//在左子树中继续查找
   else return SearchBST(T->rchild,key);    		   		//在右子树中继续查找
} // SearchBST

二叉排序树的操作-插入

若二叉排序树为空,则插入结点应为根结点
否则,继续在其左、右子树上查找

  • 树中已有,不再插入
  • 树中没有,查找直至某个结点的左子树或右子树为空为止,则插入结点应为该结点的左孩子或右孩子

插入的元素一定在叶结点上

在这里插入图片描述

二叉排序树的操作-生成

从空树出发,经过一系列的查找、插入操作之后,可生成一棵二叉排序树

在这里插入图片描述

不同插入次序的序列生成不同形态的二叉排序树

在这里插入图片描述

  • 将因删除结点而断开的二叉链表重新链接起来

  • 防止重新链接后树的高度增加

  • 删除叶结点,只需将其双亲结点指向它的指针清零,再释放它即可。

  • 被删结点缺右子树,可以拿它的左孩子结点顶替它的位置,再释放它。

  • 被删结点缺左子树,可以拿它的右孩子结点顶替它的位置,再释放它。

  • 被删结点左、右子树都存在,可以在它的右子树中寻找中序下的第一个结点(后继填

  • 充法),或是在它的左子树中寻找中序下的最后一个结点(前驱填充法),用它的值填补

  • 到被删结点中,再来处理这个结点的删除问题。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

内容未完待续,后续再次更新

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

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

相关文章

Apache Solr 9.1-(二)集群模式运行

Apache Solr 9.1-&#xff08;二&#xff09;集群模式运行 Solr是一个基于Apache Lucene的搜索服务器&#xff0c;Apache Lucene是开源的、基于Java的信息检索库&#xff0c;Solr能为用户提供无论在任何时候都可以根据用户的查询请求返回结果&#xff0c;它被设计为一个强大的文…

synchronized锁升级

假如 synchronized 是「王」身边的「大总管」&#xff0c;那么 Thread 就像是他后宫的王妃。「王」每日只能选择一个王妃陪伴&#xff0c;王妃们会想方设法争宠获得陪伴权&#xff0c;大总管需要通过一定的手段让王「翻牌」一个「王妃」与王相伴。 今日听「码哥」胡言乱语解开…

1. Linux 磁盘管理(分区、格式化、挂载)

目录 1. Linux 内核版与发行版 2. Linux中磁盘的管理(分区、格式化、挂载) 2.1 磁盘定义、分类和命名 2.2 分区的定义和划分 2.3 磁盘格式化(高级/逻辑格式化) 2.4 挂载操作 1. Linux 内核版与发行版 内核版&#xff1a;Linus Torvalds最初组织很多人完成的Linux操作系统只…

Ubuntu20.04下安装显卡驱动

环境配置 系统: Ubuntu 20.04 CPU: i5 GPU:Geforce 960M Ubuntu安装显卡驱动 1、查看当前显卡安装情况 使用glxinfo查看 https://dri.freedesktop.org/wiki/glxinfo/ $ glxinfo Command glxinfo not found, but can be installed with: sudo apt install mesa-utils需要安…

postgresql FDW概念、用法与原理小结

最近突然遇到了一批使用fdw的场景&#xff0c;整理记录一把。 一、 强大的FDW FDW (foreign-data wrapper&#xff0c;外部数据包装器)&#xff0c;可以让我们在PG中使用SQL查询极为丰富的外部数据&#xff1a; 本实例和其他pg实例中的pg库主流关系型数据库&#xff1a;Oracle…

装饰模式(decorator-pattern)

装饰模式(decorator-pattern) 文章目录装饰模式(decorator-pattern)一、手抓饼点餐系统二、要求进阶三、装饰模式概要四、装饰模式的优劣及应用场景1. 优点2.缺点3.应用场景一、手抓饼点餐系统 请设计一个手抓饼点餐系统&#xff0c;支持加配菜&#xff0c;比如里脊、肉松、火…

C++ STL

目录 1.STL诞生 2.STL概念 3.STL六大主件 4.STL容器 算法 迭代器 5.容器算法迭代器初识&#xff0c;vector 5.1vector存放内置数据类型&#xff0c; 5.2vector存放自定义数据类型&#xff0c;解引用.访问&#xff0c;指针->访问&#xff0c;存放自定义数据类型指针。迭代器…

LeetCode(Array)1365. How Many Numbers Are Smaller Than the Current Number

1.问题 Given the array nums, for each nums[i] find out how many numbers in the array are smaller than it. That is, for each nums[i] you have to count the number of valid j’s such that j ! i and nums[j] < nums[i]. Return the answer in an array. Examp…

多目标建模总结

1. 概述 在推荐系统中&#xff0c;通常有多个业务目标需要同时优化&#xff0c;常见的指标包括点击率CTR、转化率CVR、 GMV、浏览深度和品类丰富度等。为了能平衡最终的多个目标&#xff0c;需要对多个目标建模&#xff0c;多目标建模的常用方法主要可以分为&#xff1a; 多模…

Linux常用命令——top命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) top 显示或管理执行中的程序 补充说明 top命令可以实时动态地查看系统的整体运行情况&#xff0c;是一个综合了多方信息监测系统性能和运行信息的实用工具。通过top命令所提供的互动式界面&#xff0c;用热键可…

C primer plus学习笔记 —— 13、存储类别、内存管理

文章目录存储类别定义、声明和初始化的区别作用域翻译单元和文件链接属性存储期存储类别多文件共享全局变量函数的存储类别存储类别的选择分配内存&#xff08;malloc、free&#xff09;malloc和calloc创建数组方式free的重要性举例存储类别 int a 1; int *p &a; int ra…

【Stm32野火】:野火STM32F103指南者开发板烧写官方示例程序LCD无法点亮?LCD示例程序无法使用?

项目场景&#xff1a; 大家好&#xff0c;最近在使用野火STM32F103指南者开发板的时候发现官方的示例程序LCD驱动代码居然无法直接驱动LCD点亮&#xff0c;这让我百思不得其解&#xff0c;以下就是我的踩坑填坑的过程&#xff0c;希望对大家有所帮助。 野火官方资料下载文档链接…

systemd介绍

systemd是一个 Linux 系统基础组件的集合&#xff0c;提供了一个系统和服务管理器&#xff0c;运行为 PID 1 并负责启动其它程序。功能包括&#xff1a;支持并行化任务&#xff1b;同时采用 socket 式与 D-Bus 总线式激活服务&#xff1b;按需启动守护进程&#xff08;daemon&a…

与Oracle不一样的union

与Oracle不一样的union一、引言二、实验探寻union2.1 再现DM8案例2.2 再现Oracle案例2.3 实验结论一、引言 前三日&#xff0c;同事call我聊发文查询优化排序问题&#xff0c;当时联想到union自身的特性&#xff08;合并去重&#xff0c;默认排序输出结果集&#xff09;&#…

(考研湖科大教书匠计算机网络)第一章概述-第五节2:计算机网络体系结构之OSI参考模型和TCPIP参考模型

文章目录一&#xff1a;OSI参考模型&#xff08;1&#xff09;应用层&#xff08;Application Layer&#xff09;&#xff08;2&#xff09;表示层&#xff08;Presentation Layer&#xff09;&#xff08;3&#xff09;会话层&#xff08;Session Layer&#xff09;&#xff0…

STC32G 单片机系列通用定时器的用法及编程

STC32G单片机与STC15系列单片机一样有T0~T4共5个通用定时器。其功能大致相同&#xff0c;与STC15系列单片机定时器不同的是STC32G单片机的定时器每个都多了一个8位预分频器&#xff0c;如下&#xff1a;这样定时器可作为一个24位定时器使用&#xff0c;做计数器使用与分频器就没…

【Flink】浅谈Flink背压问题(1)

概述 在多线程的情况下有一个典型的模&#xff0c;型生产者消费者模型&#xff0c;该模型主要由生产者、消费者和一个大小固定的队列组成。生产者向队列发送数据&#xff0c;消费者从队列中取出数据并处理。 针对上述模型&#xff0c;如果队列属于有限长度&#xff0c;当消费者…

UE5执行Python脚本插件

1.启用UE5的Python脚本编辑器&#xff1a; 在Edit里面找到Plugins&#xff0c;然后打开插件管理器&#xff0c;搜索Python,找到 Python Editor Script Plugin并启用它。该插件也可能会自动启用&#xff08;至少我的UE5是这样的&#xff09;&#xff0c;如果已经自动启用&#…

python机器学习(一)算法学习的步骤、机器学习的应用及流程(获取数据、特征工程、模型、模型评估)

机器学习入门 机器学习中需要理论性的知识&#xff0c;如数学知识为微积分(求导过程&#xff0c;线性回归的梯度下降法)&#xff0c;线性代数(多元线性回归&#xff0c;高纬度的数据&#xff0c;矩阵等)&#xff0c;概率论(贝叶斯算法)&#xff0c;统计学(贯穿整个学习过程)&a…

Nginx使用(五)配置高可用集群示例

一、条件&#xff08;1&#xff09;需要两台Nginx服务器&#xff08;2&#xff09;需要keepalived&#xff08;3&#xff09;需要虚拟ip二、准备工作&#xff08;1&#xff09;需要两台服务器&#xff08;2&#xff09;在两台服务器安装nginx&#xff08;3&#xff09;在两台服…