-
什么是树?
-
树有哪些常见术语?
-
常见的树有哪些?
-
阐述几种B树的核心原理,mysql为什么使用B+,而不是用B树或者跳表
-
阐述红黑树的核心原理,为什么java8的hashMap使用了红黑树而不是其他结构
-
开放性问题:常见的技术栈中哪里还应用了树,集思广益
个人讲解
什么是树
树是一种数据结构,它是由n(n≥0)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的
树的定义
1、树Tree 是n(n>=)个结点的有限集T,n=0时称为空树,任意非空树中
(1)有且仅有一个特定的称为根(Root)的结点。
(2)n>1时,除根结点外的其余结点可分为m(m>=0)个互不交互的子集T1,T2…Tm,其中每个子集本身又是一颗树,并称为根的子树(Subtree)
2、从逻辑上看,树型结构具有以下特点:
(1)任何非空树中有且仅有一个结点没有前驱结点,这个结点就是树的根结点
(2)除根结点之外,其余所有结点有且仅有一个直接前驱结点
(3)包括根结点在内,每个结点可以有多个直接后继结点。
(4)树形结构是一种具有递归特征的数据结构
(5)树形结构中的数据元素之间存在的关系通常是一对多,或者多对一的关系
树的性质
(1) 非空树中的结点总数等于树中所有结点的度之和加1.
(2)度为k的非空树的第i层最多有k的(i-1)次方个结点(i>=1);
(3)深度为h的k叉树最多有k^h - 1/k-1个结点。
chatgpt推算公式
吐槽一下chatgpt的数学确实差
常见术语
1、结点的度(Degree):结点的子树个数。
2、树的度:树的所有节点中最大的度数。
3、叶结点:度为0的结点,也就是没有子结点的结点。
4、父结点:除了树的根结点外,每个结点的前驱节点称为该结点的父节点。
5、子结点:每个接结点的后续结点,个数为n,n>=0。
6、兄弟结点:具有同一个父节点的各子结点,相互为兄弟结点。
7、路径和路径长度:两个具有从属层次关系的结点和之间所有相连的结点,共同称为这两个结点之间的路径。路径长度为路径中结点的个数-1。
8、祖先结点:从树的根结点到某一结点的路径中所经过的结点,都叫做该结点的祖先结点。
9、子孙结点:某一存在子树的结点,子树上的所有结点都称为该结点的子孙结点。
10、结点的层:规定树的根结点为1层,每一层后继结点层次加1,以此类推。
11、树的深度:树中所有结点中,最大层次是该树的深度,也叫树高。
树的常见结构
各个树的性质
完全二叉树
叶子节点都在最底下两层(即叶子节点差最大是1),最后一层的叶子节点都靠左排列,并且除了最后一层其他层都必须有左右节点
二叉树基本都会基于链表实现,完全二叉树除外。下面的满二叉树、堆都是完全二叉树的特殊情况,都属于完全二叉树,所以都可以使用顺序存储法表示。完全二叉树使用数组存储的话,当我们将数组下标为 0 的位置不使用的话,那么所有的节点都满足:
如果父节点在数组中的下标位置为 n,那么左子节点在数组中的下标位置为 2 * n,右子节点在数组下标中的位置为 2 * n + 1
满二叉树
堆(大顶堆,小顶堆)
堆是完全二叉树的另一种特殊情况(即完全二叉树的条件都必须满足),针对的是节点数据的大小对比。堆中每个节点的值都必须大于等于(或者小于等于)其子树中的每个节点的值。大于等于每个子树节点的值称为大顶堆(最大堆),反正称为小顶堆(最小堆)。
二叉搜索树
二叉搜索树要求,二叉树中的每个节点都满足:左子节点的值小于父节点,右子节点的值大于父节点。即查询到每个节点后,左子树的值都比自己小,有子树的节点都比自己大
平衡二叉树
平衡二叉树的定义:任意节点的子树高度差都小于等于1,即树尽量趋近于满二叉树,本身就是让树尽量的饱满,树的高度尽量低
平衡二叉搜索树
平衡二叉搜索树 = 二叉搜索树 + 平衡二叉树。二叉搜索树在查询数据的时候可以通过判断就减少一部分数据,但是如果类似于上面整个二叉树退化成单链表,那么二叉搜索树本身也没有意义。平衡二叉树本身将树的高度降到了最低,但是如果没有二叉搜索树那样的减少数据查询的范围,那么查询一个数的时间复杂度任然是O(N),这就是二叉树的前序、中序、后续遍历
所以只有平衡二叉搜索树才有意义,才能在实际项目中解决问题,每判断一次就将数据范围减小一半,与二分查找一样,查询的时间复杂度为O(logN)。常见的平衡二叉查找树有:AVL树(自平衡二叉查找树)、伸展树(Splay Tree)、树堆(Treap)、红黑树
AVL自平衡二叉搜索树
AVL树,自平衡二叉查找树。非平衡主要发生在新增或删除一个元素的时候,那么需要通过左旋或右旋的方式,让树继续满足 平衡(高度)和搜索(父节点大于左子节点,小于右子节点)的特点。项目工程上基本都会使用红黑树,所以这里不展开研究AVL树。
阐述B树/B+树的核心原理,mysql索引为什么使用B+,而不是用B树或者跳表
B树(B-树),又叫多路平衡查找树
一个m阶B树特点如下
-
B树可以定义一个m值作为预定范围,即m路(阶)B树。
-
每个节点最多有m个孩子。
-
每个节点至少有ceil(m/2)个孩子,除了根节点和叶子节点外。
-
对于根节点,子树个数范围为[2,m],节点内值的个数范围为[1,m-1]。
-
对于非根节点,节点内的值个数范围为[ceil(m/2)-1,m-1]。
-
根节点(非叶子节点)至少有两个孩子。
-
一个有k个孩子的非叶子节点包含k-1个值。
-
所有叶子节点在同一层。
-
节点内的值按照从小到大排列。
-
父节点的若干值作为分离值分成多个子树,左子树小于对应分离值,对应分离值小于右子树
B+树
B+树是B树的变体,也是一种多路搜索树:
B+树特点,其定义基本与B树同,除了:
-
非叶子结点的子树指针与关键字个数相同;
-
非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树(B树是开区间);
-
为所有叶子结点增加一个链指针
-
所有关键字都在叶子结点出现
为什么索引为什么使用B+树索引,而不使用B树或跳表?
一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘I/O操作次数的渐进复杂度。换句话说,索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数
为什么不用B树
-
它是Btree的变种,B Tree能解决的问题,它都能解决(B Tree 解决的两大问题 是什么?【每个节点存储更多的关键字;路数更多】)
-
排序能力更强
-
因为叶子节点上有下一个数据区的指针,数据形成了链表
-
扫库,扫表能力更强
-
比如如果我们要对表进行全表扫描,只需要遍历叶子节点就可以了,不需要遍历整颗B+Tree拿到所有的数据
-
B+Tree的磁盘读写能力相对于B Tree来说更强
-
空间利用率更好:根节点和枝节点不保存数据区,所以一个节点可以保存更多的关键字,一次磁盘加载的关键字更多
-
IO交互次数更少。相对的,IO读写次数也就降低了。可减少I/O次数,磁盘读写代价更低。
-
效率更加稳定
-
B+Tree永远是在叶子节点拿数据,所以IO次数是稳定的
为什么不用跳表
我们先看一下跳表
-
三层的B+Tree就可以存储2000W的数据,查找数据最多只需要三次磁盘IO即可」。
-
「跳表是链表结构,并且通过二分查找的方式去查找数据,当存储2000W数据并且满足二分查找时,需要24层索引,24层索引分散在不同的数据页中,查找数据最多会有24次磁盘IO」
核心还是io问题,虽然跳表的写入会比B+树更优秀,但mysql是磁盘数据库且读的次数远超过写的次数,跳表当索引多了之后io次数更多
阐述红黑树的核心原理,为什么java8的hashMap使用了红黑树而不是其他结构
红黑树
红黑树不是严格意义上的平衡二叉搜索树,因为红黑树的叶子节点高度差可能达到一倍。但是我们任然认为红黑树是平衡二叉查找树,红黑树的性能是所有平衡二叉搜索树中最好的,所有项目上需要用到平衡二叉搜索树的地方基本都会使用红黑树实现。比如Java中的 HashMap, jdk 8之后当HashMap的链表节点个数大于8时,会使用红黑树,并且基本上所有的语言库中都会有红黑树的实现。当新增和删除操作后,需要让红黑树任然满足条件,会做大量的左旋、右旋以及颜色的更换
为什么要有红黑树:由于AVL严格按照左右子树高度差不大于1的规则,插入和删除操作中需要大量且复杂的操作来保持ALV树的平衡(左旋和右旋),因此ALV树适用于大量查询,少量插入和删除的场景中,需要更快速删除与插入的结构,所以就有了红黑树
顾名思义,红黑树的节点有红色和黑色两种颜色,红黑树的特点:
1、根节点是黑色的;
2、每个叶子节点都是黑色的空节点(Null),也就是说叶子节点不存储数据。
3、任何相邻的节点都不能同时为红色,也就是说红色节点中间一定有黑色节点隔开。
4、每个节点都满足,从该节点到达其可达的叶子节点的所有路径,黑色节点的个数必须相同。
鉴别红黑树
1.
2.
红黑树的基本操作:变色
为了保持路径上黑色节点个数一致,在插入时,新插入的节点我们总是认为是红色。如果插入之后某个部分符合以下规则(如图所示,2号为红色,其父节点3和叔节点8位红色),那么我们将采取变色的方法
那么这时违反了规则三。我们可以通过变色来解决。 第一步:将父节点3和叔节点8变黑 第二步,将奶奶节点5变红。
红黑树的基本操作:旋转
左旋与右旋
左旋是将某个节点旋转为其右孩子的左孩子,而右旋是节点旋转为其左孩子的右孩子
4种情况
左左
如图是红黑树的一部分,2号节点的父节点为红色,叔节点为黑色。2号节点为左节点,2号节点的父节点为左节点,所以符合左左的情况,我们进行右旋
左右
如图是红黑树的一部分,8号节点的父节点为红色,叔节点为黑色。8号节点为右节点,8号节点的父节点为左节点,所以符合左右的情况
右右
当前节点为右节点,父亲也为右节点,我们进行左旋
右左
当前节点为左节点,父亲为右节点,我们先 右旋 -> 左旋 -> 变色
出道题
将 15、13、16、11、9、7、5、3,构建成红黑树