文章目录
前言
本文是在查看了很多大佬的文章后归纳总结得出,参考文章:
https://blog.csdn.net/u014453898/article/details/112469113
https://blog.csdn.net/a519640026/article/details/106940115
https://blog.csdn.net/i6223671/article/details/86761107
BST树 — 二叉排序树
特点:
- 根节点的值大于其左子树中任意一个节点的值
- 根结点的值小于其右节点中任意一节点的值
- 这一规则适用于二叉查找树中的每一个节点。
好处:
查询的时间复杂度比链表快,链表的查询时间复杂度是O(n),二叉排序树平均是O(logn)。二叉排序树越平衡,越能模拟二分法,所以越能像二分法的查询的时间复杂度O(logn)。
二叉排序树如下图:
不足:
但是BST树有一个不足的地方,就是如果插入的结点的值的顺序,是越来越小或者越来越大的,那么BST就会退化为一条链表,那么其查询的时间复杂度就会降为O(n)。
AVL树 — 平衡二叉树
特点:
- 拥有BST树的特点:根节点的值大于其左子树中任意一个节点的值,小于其右节点中任意一节点的值,这一规则适用于二叉查找树中的每一个节点。
- AVL树上任意结点的左、右子树的高度差最大为1。
由于AVL树的第二个特点,使得,AVL树的形状肯定不会退化成一条链表的,而是“矮胖”型的树。所以能确保AVL的查找、添加、删除的平均时间复杂度都是O(logn)。
B-树 — 平衡多路查找树
B-树的特点
注:B树就是B-树,只是翻译的问题,并没有所谓的B减树
B树和AVL树(平衡二叉树) 的差别就是 B树 属于多叉树,又名平衡多路查找树,即一个结点的查找路径不止左、右两个,而是有多个。数据库索引技术里大量使用者B树和B+树的数据结构。一个结点存储多个值(索引)。
B树的阶数:M阶表示 一个B树的结最多有多少个查找路径(即这个结点有多少个子节点)。M=M路,M=2是二叉树,M=3则是三叉树。
一棵M阶B树有以下特点。
1. 每个结点的值(索引) 都是按递增次序排列存放的,并遵循左小右大原则。
2. 根结点 的 子节点 个数为 [2,M]。
3. 除根结点 以外的非叶子结点 的子节点个数 为[ Math.ceil(M/2),M]。 Math.ceil() 为向上取整。
4. 每个非叶子结点 的值(索引) 个数 = 子节点个数 -1 。最小为 Math.ceil(M/2)-1 最大为 M-1 个。
5. B树的所有叶子结点都位于同一层。
下图是一个 3阶B树:
可以看到:
1. 除 根结点 外,所有 非叶子结点 都至少有 M/2 = 1.5 取整 = 2 个结点。
2. 每个 结点中 的索引值 都是从小到大排序的
3. 所有叶子结点都在同一层中。
B-树的查找结点
从上述的 3阶B树 中,查找 结点5 的过程:
(1) 第一次读IO,把9的结点读到内存,再与目标数5比较,5是小于9的,因此往9的左边走。
(2) 第二次读IO,还是把结点读到内存中,然后比较结点中的2和6与目标值5。发现5是大于2小于6的,因此往中间路径走。
(3)第三次读IO,还是把结点读到内存中,然后发现结点中有5,因此找到目标值。
好处:
1. 在数据库查询中,以树存储数据。树有多少层,就意味着要读多少次磁盘IO。
所以树的高度越矮,就意味着查询数据时,需要读IO的次数就越少。(众所周知,读IO是一件费事的操作)
当数据量大的时候,用AVL树存的话,就算AVL是平衡树,但是也扛不住数据量大,数据量大,AVL树的树高肯定很高,那么读取数据的IO次数也会多。那么有没有办法能压缩AVL树的树高呢?这时候B树就出来了。B树的一个结点可以装多个值,读取时,是把整个结点读到内存,然后在内存中