数据结构--树与二叉树

2023-11-04

一、树的概述
1.树的基本概念
N个结点组成一对多关系的层次结构。
N = 0 为空树,N = 1 只有根结点的树,N > 1 树。

A 逻辑定义(前驱后继)
有且仅有一个根结点,除根结点外,每一个节点有且仅有一个前驱结点,每个结点可以有0个或多个后继结点。
没后继结点称为“叶子结点”(终端结点),有后继结点的称为“分支结点”(非终端结点)。
结点数目为0的树称为空树

B 递归定义
树是n(n>=0)个结点的有限集合,n=0时,称为空树。
在任意一棵非空树中满足:
a.有且仅有一个根结点
b.当n>1时,其余结点可分为m(m>0)个互不相交的有限集合T1,T2,...Tm,其中每个集合本身又是一棵树,称为根结点的子树

C 度为m的树 m叉树(易错点)
度为m的树:至少有一个结点度为m,那么一定是非空树,至少有 m + 1个结点。
m叉树:每个结点最多只能有m个孩子的树,也可以没有。m叉树是有序树,孩子不能互换。

树的逻辑结构的应用
省份地点模型 家族关系模型  商品分类模型 文件目录模型

2.相关术语
A 结点之间的关系描述
祖先结点、子孙结点、双亲结点、孩子结点、兄弟结点、堂兄弟结点
两个结点间的路径:从上往下经过的边数。
树的路径长度:树中所有结点的边数总和,有带权路径长度。

B 结点、树的属性描述
结点的层次(深度),从上往下数,默认从1开始
结点的高度,从下往上数
树的高度深度),总共多少层
结点的度:有几个孩子结点(分支),叶子结点度为0
树的度:各结点度的最大值

C 有序树和无序树
树中结点的各子树从左至右是有次序的,不能互换。
树中结点各子树从左至右是无次序的,可以互换。
具体看实际应用是否需要位置反映逻辑关系,如省份层次模型可以不需要,家族关系需要按年龄。

D 森林
森林是m棵互不相交的树的集合。m = 0 或 1 或大于 1
如全中国所有人家的家谱。

3.树的性质
A 结点与度数

除根结点外,每个结点都有一个父结点的度。结点数 = 总度数 + 1
设结点总数为N,则度为0的结点为N0,度为1的结点为N1,度为2的结点为N2,以此类推。
N = N0 + N1 + ...... + Nn
N = 1 + 0 *N0 + 1* N1 + 2*N2 + ......  + n * Nn

B 层次与结点分析(第i层的结点数)
度为m的树,第i层结点数目,最多时每个结点的孩子结点都为m,第i层为 m ^ (i - 1)
每个结点都只有1个结点,倒数第二层有m个孩子结点,有m个。
同样m叉树第i层最多有m ^ (i - 1)个结点。最少没有结点。

C 高度与结点分析
高度为h的m叉树,每个结点都有m个孩子结点,至多共有 m^0 + m^1 + ... + m^(h-1)。
高度为h的m叉树至少有h个结点。
高度为h,度为m的树至少有 h - 1 + m 个结点
具有n个结点的m叉树的最小高度为

4.树的存储结构
A 双亲表示法(顺序存储)

结点结构:关键字 + 指向双亲的位置下标。
存储结构:需要一块连续的空间存储结点。

优点:查指定结点的双亲很方便;缺点:查指定结点的孩子需要重新遍历。

B 孩子表示法(顺序+链式)

C 孩子兄弟表示法

二、二叉树的概述
1.二叉树的概念
每个结点最多只有两棵子树,可以有0个,1个(左右不一样),2个。
左右子树不能颠倒,二叉树是有序树

二叉树的五种状态:空树,只有根节点,只有左子树,只有有子树,左右子树都有。
度为2的的树是必须至少有一个结点的孩子为2。

2.几个特殊的二叉树
满二叉树:按序号层次编号,孩子结点的度都为2,没有度为1的结点,只有最后一层有叶子结点。
完全二叉树:每个结点都与的编号都与其对应的满二叉树编号相同。

二叉排序树:左子树上的关键字均小于根借点的关键字,右子树上所有结点的关键字均大于根结点的关键字。

平衡二叉树:树上任一结点的左右子树之差不超过1。-1 0 1

3.二叉树的性质
A 结点与度
非空二叉树度为0、1、2的结点个数分别为n0,n1,n2.
n = n0 + n1 + n2;n = 1 + 0*n0 + 1*n1 + 2*n2
n0 = n2 + 1;叶子结点比二分支结点多一个。

B 结点与层数
二叉树第i层至多有2^(i-1)个结点。

C 结点与高度
高度为h的二叉树至多有2^h - 1个结点。(满二叉树)
具有n个结点的完全二叉树的高度h为

D 完全二叉树的性质
完全儿叉树最有只有一个度为1的结点,即n1 = 0 或 1。
n0 = n2 + 1,n0 + n2 一定是奇数。
若n0 + n1 + n2 为偶数 2k个,则 n1 = 1,n0 = k , n2 = k -1。
若n0 + n1 + n2 为奇数 2k-1个,则 n1 = 0,n0 = k , n2 = k -1

4.二叉树的存储结构
A 顺序存储

按照完全二叉树的方式存储二叉树。
定义一个长度为MaxSize的数组t,按照从上至下、从左至右的顺序依次存储完全二叉树中的各个结点。
结点结构 TreeNode:结点中的数据元素;结点是否为空。

顺序存储下结点的分析

如果不是完全二叉树各结点顺序存储,一定要将二叉树的结点编号与完全二叉树对应起来。


最坏情况:高度为h且只有h个结点的单支树,也至少需要2^h -1 个存储单元。
因此,二叉树的顺序存储只适合存储完全二叉树。

B 链式存储
结点结构 BiTNode数据元素 ElemType data; 左右孩子指针 struct BiTNode *lchild,*rchild


n个结点的二叉树结点,共有2n个指针域,有n-1个度占用,还剩n+1个空链域。可以用于构造线索二叉树。

 

可以很方便的找个指定结点的左右孩子结点。
要找父结点只能从根结点开始遍历。
可以增加一个父结点指针,组成三叉链表,方便寻找父结点。

 

5.二叉树的遍历
遍历:按照某种次序把所有结点都访问一遍。
层次遍历:基于树的层次特性确定的次序规则。
先中后序遍历:基于树的递归特性确定的次序序列。
先序(NLR)根左右,中序(LNR)左根右,后序(NRL)左右根。

遍历算术表达式

代码实现

|

层序遍历


不同二叉树的先中后层序列都可能对应多个二叉树形态。因此,只给出其中一种不能唯一确定。

 6.树和二叉树的转换


 

树和森林
森林和二叉树的转换

7.树的遍历




三、树的应用
1.线索二叉树
A 线索二叉树的作用
二叉树的中序遍历序列:D G B E A F C

能否从一个指定结点开始继续中序遍历?
如何找到指定结点在中序遍历序列中的前驱和后继?从根结点出发往下访问。
这样操作很不方便,遍历操作必须从根结点开始出发。

n个结点的二叉树有n+1个空链域,可用来记录前驱、后继的信息。
指向前驱或后继的指针称为线索,用左孩子指针充当前驱线索,右孩子指针充当后继线索。
 

B 线索二叉树的存储结构

C 三种线索二叉树

2.二叉树线索化
A 中序线索化

B 先序线索化

C 后序线索化

3.在线索二叉树中找前驱和后继
A 中序线索二叉树

B 先序线索二叉树

C 后序线索二叉树

2.二叉排序树(BST,Binary Search Tree)
A 定义

左子树上的结点值 < 根结点的值  < 右子树上结点值。
左子树和右子树又各是一个二叉排序树。
进行中序遍历可得到一个递增的有序序列。

B 查找
若树为非空,目标值与根结点值进行比较,相等查找成功,小于根结点在左子树查找,否则在右子树查找。查找成功返回结点指针,查找失败返回null。
循环实现最坏空间复杂度为O(1),递归实现最坏空间复杂度为O(h)。

C 插入
若原二叉树为空,则直接插入结点;否则,若关键字小于根结点的值,则插入左子树;否则插入右子树。
如按照序列{50,66,60,26,21,30,76,68}构造二叉排序树。
不同的序列可能得到相同或者不同的二叉排序树。

D 删除
先搜索找到目标结点,
若被删除的结点z是叶子结点,则直接删除,不会破坏二叉树的性质。
若被删除的结点z只有一棵左子树或右子树,则让z的子树成为z父结点的子树,替代z的位置。
若被删除的结点z有左右两棵子树,让z的直接前驱或后继替代z(这里的直接前驱和后继指遍历后的前驱后继),删除直接前驱或后继,变成判断直接前驱或后继的左右子树情况。。

E 查找效率分析
查找长度,在查找运算中,需要对比关键字的次数称为查找长度,反映查找操作时间复杂度。
若树高为h,找到最下层的一个结点需要对比h次。
最好情况,n个结点的二叉树最小高度为 logn + 1 , 平均查找长度为 log
最坏情况,每个结点只有一个分支,树高h = 结点树n。平均查找长度 = O(n)

查找成功的平均查找长度ASL
第一层 1次 第二层 2次  第h层 h次  
[ 1 * (第1层结点数) + 2  * (第2层结点数) + ... + h * (第h层结点数)  ]  /  n

查找失败的平均查找长度ASL


3.平衡二叉树(AVL树)
A 概述

对n个序列的顺序查找,时间复杂度为O(n),将n个序列进行分层构造成树,可以优化查找速度,时间复杂度为树的高度O(h)。
构造一棵平衡二叉树可使得树的高度最小,即左右子树的高度之差不超过1。
结点的平衡因子 = 左子树高 - 右子树高 -1 0 1

B 平衡二叉树的插入
在二叉排序树中插入新的结点后,如何保持平衡?
插入一个结点后可能会使查找路径上的所有结点都有可能受到影响。从插入点往回找到第一个不平衡结点,调整以该结点为根的子树。每次调整的对象都是“最小不平衡子树”。只要将最小不平衡子树调整平衡,则其他祖先结点都会恢复平衡。

C 调整最小不平衡子树A(重点)
LL:在A的左孩子的左子树插入导致不平衡
RR:在A的右孩子的右子树插入导致不平衡
LR:在A的左孩子的右子树中插入导致不平衡
RL:在A的右孩子的左子树中插入导致不平衡

D 查找效率分析
若树高为h,则最坏情况下,查找一个关键字最多需要对比h次,即查找操作的时间复杂度不可能超过O(h)。

平衡二叉树--树上任一结点的左子树和右子树的高度之差不超过1。
假设以Nh表示深度为h的平衡树中含有的最少结点数。n0 = 0,n1 = 1,n2 = 2
并且有 nh = n h-1  + n h-2  + 1
可以证明含有n个结点的平衡二叉树的最大深度为O(log),平衡二叉树的平均查找长度为O(log)


4.哈弗曼树
A 概述

结点的权:结点关键字表示的数值。
结点的带权路径长度:从树的根到该结点的路径长度(经过的边数)与该结点上权值的乘积
树的带权路径长度:树中所有结点的带权路径长度之和。WPL

在含有n个带权叶结点的二叉树中,其中带权路径长度(WPL)最小的二叉树称为哈夫曼树,也成最优二叉树。

B 构造


C 哈夫曼编码
固定长度编码:对每个字符用相等长度的二进制位表示。如A--00 B--01 C--10 D--11
对80个C,10个选A,8个B,2个D,总的二进制长度为 100 * 2 = 200 bit
可变长度编码:允许对不同字符用不等长的二进制位表示。根据出现频率大小构造哈弗曼树,得如C--0 A--10 B--111 D--110
前缀编码:一组编码内,没有一个编码是另一个编码的前缀,则称前缀编码。
在连续编码串内才能识别出对应的编码。

哈夫曼树可用于数据压缩。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据结构--树与二叉树 的相关文章

  • 【机器学习】噪声数据的理解

    文章目录 一 噪声数据 1 1 分箱 1 2 回归 1 3 聚类 1 4 其他 二 数据清理作为一个过程 2 1 偏差检测 2 1 1 使用 元数据 关于数据的数据 2 1 2 编码格式 存在使用不一致 数据表示不一致 2 1 3 字段过载

随机推荐

  • C语言编程中的8位、16位、32位整数的分解与合并

    在单片机的编程中对于8位 16位 32位整数的分解与合并用的比较多 今天做了简要学习 后面还需要加以总结 练习在VC 6 0编程环境中进行 源程序 include
  • pikachu靶场--SQL inject--数字型(post)/字符型(get)/搜索型/xx型注入【4.1】~【4.4】

    目录 一 概述 二 数字型注入 post 三 字符型注入 get 四 搜索型注入 以搜索k为例 五 xx型注入 一 概述 在owasp发布的top10排行榜里 注入漏洞一直是危害排名第一的漏洞 其中注入漏洞里面首当其冲的就是数据库注入漏洞
  • python 变量赋值 修改之后 原值改变

    python 是一种动态语言 因此变量的类型和值 在运行时均可改变 当我们将一个变量赋值给另一个变量时 实际上是将变量的引用地址传递给新的变量 这意 味着新旧变量将指向同一个位置 因此 在更改其中一个变量的值时 另一个变量的值也会被更改 i
  • pig对应sql的基本命令

    1 从文件导入数据 1 Mysql Mysql需要先创建表 CREATE TABLE TMP TABLE USER VARCHAR 32 AGEINT IS MALE BOOLEAN CREATE TABLE TMP TABLE 2 AGE
  • 【Java】final关键字的细节注意(八)

    这节内容较简单 而且内容较少 课程源自韩顺平老师的Java课程 final关键字的使用 final的需要注意的细节
  • Android UI 基础-坐标系、角度(弧度)、颜色

    目录 1 坐标系 1 1 屏幕坐标系和数学坐标系的区别 1 2 View的坐标系 1 3 MotionEvent中 get 和 getRaw 的区别 1 4 核心要点 2 角度与弧度 2 1 角度与弧度的定义 2 2 角度和弧度的换算关系
  • linux 进入目录命令

    直接进入计算机目录下 常用指令 cd home 进入 home 目录 cd 返回上一级目录 cd 返回上两级目录 cd 进入个人的主目录 cd user1 进入个人的主目录 cd 返回上次所在的目录 ls 显示文件或目录 l 列出文件详细信
  • 移动端常见meta设置

    1 设置viewport 这句话设置viewport的宽为设备的宽 禁止用户进行缩放 此外 常见参数设置 a width 宽度 数值 device width 默认为980 b height 高度 数值 device height c in
  • 手写一个根据目录自动生成的路由

    文章目录 一 起因 二 思索 三 测试效果 四 项目代码 一 起因 最近研究了一下阿里dva的quickstart 其中路由配置是手动添加 如下 先将要显示的页面导入router js 然后配置 其中path products 是配置的路由
  • 在pycharm中配置变量

    实验目的 python run classifier py task name MRPC do train true do eval true data dir GLUE DIR MRPC vocab file BERT BASE DIR
  • es 索引类型与分词器调整与迁移

    索引最好起别名 方便索引调整 1 创建新索引 PUT index v2 settings number of shards 5 number of replicas 1 mappings doc dynamic strict propert
  • Python爬虫中文乱码问题

    我们在爬虫输出内容时 常常会遇到中文乱码情况 以如下网址为例 https chengdu chashebao com yanglao 19077 html 在输出内容时 出现如下图的情况 解决爬虫中文乱码的步骤 网址编码为gbk 查看网页源
  • shell与shell脚本(一)基本概念与常用的shell命令

    前言 像linux windows等的操作系统 都很大程度上地便利了我们操作计算机的能力 计算机之所以能高效处理用户指令 是因为CPU 更细致地讲 是因为CPU中的内核 也就是我们所说的运算器 控制器和寄存器 当然 我们在使用计算机是 不可
  • 四、同步方法与异步方法及回调函数

    解释一下同步方法与异步方法以及回调函数的关系 若不想很深入的了解这方面内容 可以记住以下结论 对于同时有同步方法和对应异步方法的函数 我们常用异步方法 用独立线程去处理该函数 提高用户的体验 异步方法由于我们需要等待某种事件的发生 例如当前
  • mysql插入数据时,在数据库和表的编码都是utf-8的情况下,还是出现乱码

    Mysql插入数据时 在数据库和表的编码都是utf 8的情况下还是会出现乱码 解决方法 首先先确定自己的数据库的编码是否是utf 8 查看数据库字符集 将sct换为自己的数据库的名字 SHOW CREATE DATABASE sct 会看到
  • vue 项目 基于axios 对常用5种(POST、GET、PUT、DELETE、PATCH)请求进行封装

    一 安装axios 使用 npm npm install axios save 使用 cnpm cnpm install axios save 使用 yarn yarn add axios save 建议使用cnpm 二 src目录下新建l
  • c语言 什么时候需要动态分配内存?

    我讲解一下c语言中动态分配内存的函数 可能有些初学c语言的人不免要问了 我们为什么要通过函数来实现动态分配内存呢 系统难道不是会自动分配内存吗 既然有人会问这样的问题 那么我在这里好好的讲解一下吧 首先让我们熟悉一下计算机的内存吧 在计算机
  • qt中的线程

    目前我暂时会两种线程方式 一种是继承QTHRead 另一种是movetothread 相对二样 第二种好一些 先来介绍一下第一个方法 继承QTHread public A QThread void run 重新run函数 public B
  • python sqlalchemy 多对多

    调用Column创建字段 加类型 from sqlalchemy import Table Column Integer String DATE ForeignKey 调用操作链接 反查 from sqlalchemy orm import
  • 数据结构--树与二叉树

    一 树的概述1 树的基本概念 N个结点组成一对多关系的层次结构 N 0 为空树 N 1 只有根结点的树 N gt 1 树 A 逻辑定义 前驱后继 有且仅有一个根结点 除根结点外 每一个节点有且仅有一个前驱结点 每个结点可以有0个或多个后继结