数据结构-树

本文深入探讨了数据结构中的树型数据,包括二叉树的定义、分类、存储方式、遍历算法以及二叉查找树的特性。特别地,介绍了红黑树作为自平衡二叉查找树的原理和平衡策略。此外,还提及了多路查找树,如B树和B+树在数据库索引中的应用。内容涵盖树的深度和广度遍历、时间复杂度分析以及它们在实际问题中的应用,如HashMap的实现。
摘要由CSDN通过智能技术生成

一、树
(一)概述
1、树的定义
现实中数据的逻辑关系并不都是线性关系,在实际场景中,常常存在着一对多,甚至是多对多的情况,所以需要树型数据结构
树(tree)是n(n≥0)个节点的有限集。当n=0时,称为空树。在任意一个非空树中,有如下特点。
有且仅有一个特定的称为根的节点。
当n>1时,其余节点可分为m(m>0)个互不相交的有限集
每一个集合本身又是一个树,并称为根的子树
图示:
在这里插入图片描述
节点1是根节点(root),没有父节点
节点5、6、7、8是树的末端,没有“孩子”,被称为叶子节点(leaf)
节点2、3、4、是树的中端,有父节点,有孩子,被称为中间节点或枝节点
图中的虚线部分,是根节点1的其中一个子树
树的最大层级数,被称为树的高度或深度,上图这个树的高度是4。树的层级定义如下:
在这里插入图片描述

注:注意高度、深度、层定义的顺序

2、树的分类
在这里插入图片描述
(二)二叉树
1、定义
二叉树(binary tree)是树的一种特殊形式。二叉,顾名思义,这种树的每个节点最多有2个孩子节点。注意,这里是最多有2个,也可能只有1个,或者没有孩子节点。
图示:
在这里插入图片描述
二叉树节点的两个孩子节点,一个被称为左孩子(left child),一个被称为右孩子(right child)。这两个孩子节点的顺序是固定的,左孩子小于右孩子。
2、树的存储
二叉树属于逻辑结构,可以使用链表和数组进行存储。
(1)链表存储
在这里插入图片描述
二叉树的每一个节点包含3部分
存储数据的data变量
指向左孩子的left指针
指向右孩子的right指针
(2)数组存储
使用数组存储时,会按照层级顺序把二叉树的节点放到数组中对应的位置上。如果某一个节点的左孩子或右孩子空缺,则数组的相应位置也空出来
在这里插入图片描述

对于一个稀疏的二叉树(孩子不满)来说,用数组表示法是非常浪费空间的,所以二叉树一般用链表存储实现。(二叉堆除外)

树寻址方式:
一个父节点的下标是n,那么它的左孩子节点下标就是2×n+1、右孩子节点下标就是2*(n+1)
比如根节点下标是0,那么左子节点下标是1,右子节点下标是2。以此类推即可
3、分类
(1)满二叉树
一个二叉树的所有非叶子节点都存在左右孩子,并且所有叶子节点都在同一层级上,那么这个树就是满二叉树
在这里插入图片描述

注:所有分支的叶子节点都必须齐全
(2)完全二叉树
对一个有n个节点的二叉树,按层级顺序编号,则所有节点的编号为从1到n。如果这个树所有节点和同样深度的满二叉树的编号为从1到n的节点位置相同,则这个二叉树为完全二叉树
在这里插入图片描述

满二叉树要求所有分支都是满的;而完全二叉树只需保证最后一个节点之前的节点都齐全即可。
注:只需要满足倒数第二层的所有节点都存在,叶子节点不需要全部齐全
(3)二叉查找树(BST)
1)定义
二叉查找树(binary search tree),二叉查找树在二叉树的基础上增加了以下几个条件:
如果左子树不为空,则左子树上所有节点的值均小于根节点的值
如果右子树不为空,则右子树上所有节点的值均大于根节点的值
左、右子树也都是二叉查找树
图示:
在这里插入图片描述

二叉查找树要求左子树小于父节点,右子树大于父节点,正是这样保证了二叉树的有序性
2)操作
查找树
如上图如果需要查的值为4,查询顺序是,从根节点开始4<6,查左子节点3,3<4,查右子节点,则刚好为4
如果节点总数是n,那么搜索节点的时间复杂度就是O(logn),和树的深度是一样的。这种方式正是二分查找思想
插入值:从根节点开始一次比较,找到值存储位置
插入节点:通过递归方式实现,当插入一个data时,就从根节点开始比较,直到找到某个节点的左右或子节点为null时,就把新添加的节点插入的该节点左侧或右侧
4、二叉树遍历(以二叉查找树为例)
(1)深度遍历
深度遍历是先把一个子树遍历到底再去遍历另一边子树,具体又分为前序、中序、后序遍历,实际看根节点(父节点)的优先级为依据
前序判断顺序为根节点-左子节点-右子节点,中序判断顺序为左子节点-根节点(父节点)-右子节点,后序判断顺序是左子节点-根节点(父节点)-右子节点
示例:如图二叉查找树
在这里插入图片描述

前序遍历节点搜索顺序:10-8-7-9-11-12
中序遍历节点搜索顺序:7-8-9-10-11-12
后续遍历节点搜索顺序:7-9-8-12-11-10
广度遍历节点检索顺序:10-8-11-7-9-12
(2)广度遍历
二叉树按照从根节点到叶子节点的层次关系,一层一层横向遍历各个节点。
二叉树同一层次的节点之间是没有直接关联的,利用队列可以实现
在这里插入图片描述

如图:先把根节点1放入队列,然后判断队列是否有数据,如果有就取出队头数据比较,同时把子节点2和3放入队列,依次放入取出比较,直到搜索完整个树
在图中节点搜索顺序是1-2-3-4-5-6
5、时间复杂度
二叉查找树的插入和查找时间复杂度为:O(logn)极端情况下二叉查找树退化成链表,时间复杂度为O(n),所以需要平衡二叉查找树。
6、应用
非线性数据:菜单,组织结构、家谱等等
线性数据:二叉查找树
二叉查找树是有序的,我们只需要中序遍历,就可以在 O(n) 的时间复杂度内,输出有序的数据序列。二叉查找树的性能非常稳定,扩容很方便(链表实现)

(三)红黑树
1、概述
二叉查找树极端情况下退化成了链表,由于树的深度变得多了,查找的效率也会大幅下降所以需要对这种二叉树进行自平衡,红黑树就是一种自平衡的二叉查找树。
比如按照顺序插入节点10、9、8、7、6、5、4,那么二叉查找树的形状类似左斜杠“/”,实际就是一个链表
2、红黑树定义
红黑树除了有二叉查找树(BST)的特征外,还有以下特征:
每个节点要么是黑色,要么是红色
根节点必须是黑色
每个叶子节点都是黑色的空结点(NIL结点)(为了简单期间,一般会省略该节点)
如果一个节点是红色的,则它的子节点必须是黑色的(父子不能同为红)
从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点(平衡的关键)
新插入节点默认为红色,插入后需要校验红黑树是否符合规则,不符合则需要进行平衡
注:一个红黑树必须满足这些规则,对红黑树进行添加或者删除操作时可能会破坏这些规则,所以红黑树有维持树平衡策略:左旋转、右旋转和颜色反转
3、红黑树平衡策略
(1)左旋(RotateLeft)
逆时针旋转红黑树的两个结点,使得父结点被自己的右孩子取代,而自己成为左孩子
在这里插入图片描述

左旋就是以某个节点为中心,把该节点往左子节点方向旋转。节点成为左子节点,该节点要关联先前右子节点的左子节点为自己的右子节点,即图中X节点需要关联节点b
(2)右旋(RotateRight)
顺时针旋转红黑树的两个结点,使得父结点被自己的左孩子取代,而自己成为右孩子
在这里插入图片描述

右旋就是以某个节点为中心,把该节点往右子节点方向旋转。节点成为右子节点,该节点要关联先前左子节点的右子节点为自己的左子节点,即图中X节点需要关联节点c
(3)颜色反转
红黑树新插入一个节点是红色的,如果插入节点与父节点、叔叔节点同为红色,这种情况违反了红黑树的规则,需要将红色向祖辈上传,把父节点和叔叔节点红色变为黑色,祖父节点从黑色变为红色,如果祖父节点是根节点,那么根节点还是保持黑色
在这里插入图片描述

4、红黑树插入节点规则
1.第一层。即插入根节点,修改根节点颜色为黑即可
2.第二层。插入根节点的左右子节点,满足左节点小于根节点,右节点大于根节点,其他不用调整
3.第三层往下所有层。
3.1如果父节点是黑色,直接插入
3.2如果父节点和叔叔节点都存在且都是红色。只需要颜色反转
3.3如果父节点是红,叔叔节点是黑或者没有,需要自旋。
3.3.1插入节点是左子树的左子节点,以祖父节点为中心右旋;插入节点是左子树的右子节点,那么先以父节点为中心左旋,再以祖父节点为中心右旋。
3.3.2插入节点是右子树的右子节点,以祖父节点为中心左旋。插入节点是右子树的左子节点,那么先以父节点为中心右旋,再以祖父节点为中心左旋
在三层及以上的树插入节点注意事项
在这里插入图片描述

图释:
1.角色定义。以节点10为中心,父节点是19,祖父节点是9,叔叔节点是5
2.子树定义。左子树还是右子树是父节点相对于祖父节点而言,如果父节点是祖父节点左节点,就是左子树,父节点是祖父节点右节点,就是右子树。
示例1:假如以节点5为中心,由于节点5是节点9的左子节点,所以节点5构成左子树,同时如果以节点6为中心,节点6是节点5的右子节点,所以节点6构成右子树
示例2:如图节点10就是右子树19的左子节点,节点32是右子树19的的右子节点,假设新插入节点16,插入规则使用3.3.2
3.自旋思路
如果插入节点是左子树的左子节点,树的形状类似左斜杠“/”。在3.3.1规则中,插入左子树的右子节点,就是通过左旋把红节点先转为“/”形状,然后再对祖父节点右旋
示例:如果插入新结点25,那么先以父节点24为中心左旋,得到24-25-32的“/”排列,再以祖父节点32为中心右旋,则节点19的右子节点就是节点25,节点25的左子节点是24,右子节点是32,满足红黑树规则
如果插入节点是右子树的右子节点,树的形状类似右斜杠“\”。在3.3.1规则中,插入右子树的左子节点,就是通过左旋把红节点先转为“\”形状,,然后再对祖父节点左旋

注:插入节点整体思路:在进行插入规则判定时,先看插入节点的层级,再看父节点是否是红色,最后看叔叔节点是否存在且是否红色
算法动画演示地址:https://www.cs.usfca.edu/~galles/visualization/RedBlack.html
5、时间复杂度:O(logn)
6、应用
在JDK1.8中HashMap使用数组+链表+红黑树的数据结构。内部维护着一个数组table,该数组保存着每个链表的表头结点或者树的根节点

(四)多路查找树
1、概述
多路查找树(muitl-way search tree),其每一个节点的孩子数可以多于两个,且每一个节点处可以存储多个元素
2、B树和B+树
MySQL索引原理

(五)二叉堆
1、概述
二叉堆本质上是一种完全二叉树
2、分类
(1)大顶堆(最大堆)
最大堆的任何一个父节点的值,都大于或等于它左、右孩子节点的值
在这里插入图片描述

(2) 小顶堆(最小堆)
最小堆的任何一个父节点的值,都小于或等于它左、右孩子节点的值
在这里插入图片描述

二叉堆的根节点叫作堆顶。最大堆和最小堆的特点决定了:最大堆的堆顶是整个堆中的最大元素;最小堆的堆顶是整个堆中的最小元素
3、存储原理
完全二叉树比较适合用数组来存储。用数组来存储完全二叉树是非常节省存储空间的。因为我们不需要存储左右子节点的指针,单纯地通过数组的下标,就可以找到一个节点的左右子节点和父节点。
在这里插入图片描述

从图中我们可以看到,数组中下标为 i 的节点的左子节点,就是下标为 i∗2 的节点,右子节点就是下标为 i∗2+1 的节点,父节点就是下标为 i/2 取整的节点
4、应用
优先队列
利用堆求 Top K问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值