erchashu

1,344 阅读7分钟

一、二叉树

1、二叉树:树的每个节点最多只能有两个子节点;并且二叉树的子节点称为“左子节点”和“右子节点”。

2、满二叉树:在一棵二叉树中。如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。

 

3、完全二叉树:完全二叉树从根结点到倒数第二层满足完美二叉树,最后一层可以不完全填充,其叶子结点都靠左对齐。

4、遍历树 : 是根据一种特定的顺序访问树的每一个节点。比较常用的有前序遍历,中序遍历和后序遍历。而二叉搜索树最常用的是中序遍历。

  ①、中序遍历:  左子树——》根节点——》右子树

  ②、前序遍历:  根节点——》左子树——》右子树

  ③、后序遍历:  左子树——》右子树——》根节点


二、二叉排序树

二叉排序树,又称二叉查找树、二叉搜索树、B树。

二叉排序树是具有下列性质的二叉树:
  1. 若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  2. 若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
  3. 左、右子树也分别为二叉排序树。


二叉搜索树作为一种数据结构,其查找、插入和删除操作的时间复杂度都为O(logn),底数为2。

实际情况下,二叉搜索树的效率应该在O(N)和O(logN)之间,这取决于树的不平衡程度。


三、平衡二叉树的定义

平衡二叉树:任意的左右子树高度差的绝对值不超过1,将这样的二叉树称为平衡二叉树,二叉平衡树前提是一个二叉排序树。

由于普通的二叉查找树会容易失去”平衡“,极端情况下,二叉查找树会退化成线性的链表,导致插入和查找的复杂度下降到 O(n) ,所以,这也是平衡二叉树设计的初衷。

那么平衡二叉树如何保持”平衡“呢?根据定义,有两个重点,
  1. 一是左右两子树的高度差的绝对值不能超过1,
  2. 二是左右两子树也是一颗平衡二叉树。
  3. 三是二叉平衡树前提是一个二叉排序树。


1,AVL树(平衡二叉树)

AVL树是带有平衡条件的二叉查找树,一般是用平衡因子差值判断是否平衡并通过旋转来实现平衡,左右子树树高不超过1,和红黑树相比,AVL树是严格的平衡二叉树,平衡条件必须满足(所有节点的左右子树高度差不超过1)。不管我们是执行插入还是删除操作,只要不满足上面的条件,就要通过旋转来保持平衡,而旋转是非常耗时的,由此我们可以知道AVL树适合用于插入与删除次数比较少,但查找多的情况 。

2、红黑树

一种二叉查找树,但在每个节点增加一个存储位表示节点的颜色,可以是红或黑(非红即黑)。通过对任何一条从根到叶子的路径上各个节点着色的方式的限制,红黑树确保没有一条路径会比其它路径长出两倍,因此,红黑树是一种弱平衡二叉树(由于是弱平衡,可以看到,在相同的节点情况下,AVL树的高度低于红黑树),相对于要求严格的AVL树来说,它的旋转次数少,所以对于搜索,插入,删除操作较多的情况下,我们就用红黑树。


四、总结

1、树:无非就是前中后序遍历、二叉树、二叉搜索树、平衡二叉树,更高级一点的有红黑树、B树、B+树。。。

2、红黑树设计原理:

二叉排序树:左边的比根节点小,右边的比根节点大。而且左右子树都是二叉排序树;

但是,在一些极端情况,比如插入序列是有序的,就会出现退化的情况:有序序列,二叉排序树退化成链表。所以才要用平衡树,在插入的时候同时调整这颗树,让它的节点尽可能均匀分布。

有序序列,二叉排序树退化成链表 

红黑树其实就是平衡树的一种,它的复杂的定义和规则,最后都是为了保证树的平衡性,而红黑树可以保证树的平衡性。

那为什么要保证树的平衡性呢?

因为树的查找性能取决于树的高度,让树尽可能平衡,就是为了降低树的高度。

而java中有一个数据结构底层就是红黑树:treeSet


五、B树和B+树

1、B树(或B-树、B_树)是一种多路搜索树(并不是二叉的)

B树是一种多路搜索树,它的每个节点可以拥有多于两个孩子节点。M路的B树最多能拥有M个孩子节点。

这是一个3路的B树,每个节点做多可以拥有3个孩子,同样是搜索树;

那为什么是多路呢?是为了进一步降低树的高度,因为路数越多,树的高度越低,

那如果设计成无限多路可以吗?不限制路数,B树就退化成一个有序数组了。

B树一般用在做文件系统的索引比较多。

那为什么文件系统的索引用B树,不用红黑树或者有序数组呢?

因为:文件系统和数据库的索引都是存在硬盘上的,并且如果数据量大的话,不一定能一次性加载到内存中。

如果一棵树都无法一次性加载进内存,那该怎么查找呢?

用B树的多路存储原理,可以每次加载B树的一个节点,然后一步步往下找。

假如:内存一次性只能加载2个数,那么长的有序数组是无法一次性进内存的。若我们把它组织为一个三路的B树,这样每个节点最多有2个数,查找的时候,每次载入一个节点进内存就行。如上图。

如果在内存中,红黑树比B树效率更高,但是涉及到磁盘操作,B树就更优了。

2、B+树

B+树是在B树的基础上进行改造,它的数据都在叶子节点,同时叶子节点之间还加了指针形成链表。


为什么这样设计?

这是和业务场景相关的,数据库中select数据,不一定只选一条,很多时候会选多条,比如按照id排序后选10条。如果是多条的话,B树需要做局部的中序遍历,可能要跨层访问。而B+树由于所有数据都在叶子结点,不用跨层,同时由于有链表结构,只需要找到首尾,通过链表就能把所有数据取出来了。

2、既然hash比B+树更快,为什么mysql还用B+树来存索引呢?

这和业务场景有关。如果只选一个数据,那确实是hash更快。但是数据库中经常会选择多条,这时候由于B+树索引有序,并且又有链表相连,它的查询效率比hash就快很多了。

而且数据库中的索引一般是在磁盘上,数据量大的情况可能无法一次装入内存,B+树的设计可以允许数据分批加载,同时树的高度较低,提高查找效率。