(一)二叉树
二叉树指的是每个节点最多只能有两个子树的有序树。
二叉树特点
- 每个结点最多有两颗子树,所以二叉树中不存在度大于2的结点。
- 左子树和右子树是有顺序的,次序不能任意颠倒。
- 即使树中某结点只有一棵子树,也要区分它是左子树还是右子树。
二叉树的分类
- 斜树:左斜树(所有的结点都只有左子树)、右斜树(所有的结点都只有右子树)。
- 满二叉树:1.椰子结点只能出现在最下层。2.非叶子结点的度一定是2。3.同样深度,满二叉树结点个数最多,叶子数最多
- 完全二叉树:编号为i(1<=i<=n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同
二叉树的存储
- 顺序存储:按照数组模式存储,数组下标从上往下从左往右标注。
- 二叉链表:链表存储,结点数据定义为:左孩子指针--数据域-右孩子指针
二叉树的遍历
- 前序遍历:根结点出发,当第一次到达结点时就输出结点数据,按照先向左在向右的方向访问。
- 中序遍历:根结点出发,当第二次到达结点时就输出结点数据,按照先向左在向右的方向访问。
- 后序遍历:根结点出发,当第三次到达结点时就输出结点数据,按照先向左在向右的方向访问。
- 层序遍历:按照树的层次自上而下的遍历二叉树。
复杂度问题
空间复杂度:无论是那种遍历方式,都需要一个辅助栈来存储,每个节点都要进栈和出栈,不过是顺序的区别,所以空间复杂度始终为O(n)。
时间复杂度:通过遍历循环的方式获取,足够大时,时间复杂度为O(n)
(二)B树
B树也称B-树,它是一颗多路平衡查找树。M定义节点的分支个数。
特点
- 每个结点最多只有m个子节点。
- 每个结点最多有m-1个关键字。
- 每个非叶子节点(除了根)具有至少⌈ m/2⌉子节点。
- 根节点最少可以只有1个关键字。
- 具有k个子节点的非叶节点包含k -1个键。
- 所有叶子节点都位于同一层,或者说根节点到每个叶子节点的长度都相同。
B树的插入
- 如果该结点元素个数小于m-1,直接插入
- 如果该结点元素个数等于m-1,引起结点分裂,取中间元素(偶数个数,中间两个随机选取),插入到父节点中
- 重复之前操作,直到所有节点符合B树的规则。
B树的删除
- 1.如果删除的是叶子结点的元素,且删除之后还是大于m/2,则直接删除
- 2.如果删除的是叶子结点的元素,但是删除之后小于m/2,如果兄弟结点借元素之后,兄弟结点仍满足大于m/2,则将父节点的元素移到该结点,将兄弟结点的元素移动到父节点。
- 3.如果删除的是叶子结点的元素,但是删除之后小于m/2,如果兄弟结点借元素之后,兄弟结点借完之后都不满足大于m/2,则需要将父节点的元素移到该结点,然后跟兄弟结点合并。
- 4.如果删除的是非叶子结点,需要将后继key覆盖要删除的key,将后继key所在子支删除,继续判断该结点是否满足m/2,如果满足就删除完成,如果不满足,且子支为非叶子结点,继续步骤4,如果子支为叶子结点,则走2和3.
复杂度问题
B树的复杂度和B+树类似,统一到B+树中讨论。
B+树
B+树其实就是对B树的改造。
特点
- 根节点至少一个元素
- 非根节点元素范围为:m/2 <= k <= m-1
- B+树有两种类型的节点:内部结点(也称索引结点)和叶子结点。内部节点就是非叶子节点,内部节点不存储数据,只存储索引,数据都存储在叶子节点。
- 内部结点中的key都按照从小到大的顺序排列,对于内部结点中的一个key,左树中的所有key都小于它,右子树中的key都大于等于它。叶子结点中的记录也按照key的大小排列。
- 每个叶子结点都存有相邻叶子结点的指针,叶子结点本身依关键字的大小自小而大顺序链接。
- 父节点存有右孩子的第一个元素的索引。
B+树的插入
- 1.如果结点中元素小于m-1,则直接插入。
- 2.如果插入结点之后大于m-1,则将原有结点分裂成两个,如果父节点不存在,则创建内部节点,存储右孩子结点第一个元素的索引,将数据插入对应的结点,分裂的两个结点指针相连。
- 3.分裂成两个,如果父节点存在,则将右孩子结点的第一个元素的索引,插入父节点。
- 3.当父节点达到m时,将右孩子结点的第一个元素的索引用来创建父节点,原父节点分裂,分别存储右孩子结点的第一个索引。
B+树的删除
删除操作因为有指针的存在,就不需要通过父节点了,直接通过兄弟结点移动即可。然后更新父节点的索引。
删除步骤同B树借元素的逻辑。删除后不足借兄弟结点的元素,修改父节点的索引,不足时进行合并,更新父节点索引。
B+树的时间复杂度
假设一个含有N个值,阶为n的B+树。
很显然,查询需要按照树结构从上往下查询,当树越高,查询的复杂度越高,也就是当分叉最少的时候,即只分为两叉时,复杂度越高。
而每个节点的数值为:n/2 <= k <= n-1,同时,二叉的结构,又将数分成了两颗子树,得到以下公式:(n/2)^h >=N/2;
意思是,每个节点有至少n/2个选择对应下一个节点,共有h次这样的选择,因此,时间复杂度为O(log N).
B+树在mysql中的使用
主键索引
联合索引
叶子结点最后存储的是主键,因为联合索引是非聚簇索引
2-3树
红黑树
红黑树,Red-Black Tree 「RBT」是一个自平衡(不是绝对的平衡)的二叉查找树(BST),
特点
- 1.每个节点都有红色或黑色
- 2.树的根始终是黑色的 。
- 3.没有两个相邻的红色节点(红色节点不能有红色父节点或红色子节点,并没有说不能出现连续的黑色节点)
- 4.从节点(包括根)到其任何后代NULL节点(叶子结点下方挂的两个空节点,并且认为他们是黑色的)的每条路径都具有相同数量的黑色节点
- 5.每个叶子结点null为黑色
红黑树的插入
- 1.插入数字,如果是root节点,则标记为黑色
- 2.插入数字,父节点为根结点,则标记为红色
- 3.插入数字,新节点的父节点为红色。此时因为不允许有两个连续的红色结点,所以需要调整:
- 3.1.父节点的兄弟结点为红色,则将父节点和父节点的兄弟结点标为黑色,并将祖先结点标为红色,此时,需要判断祖先结点的父节点属性。
- 3.2.父节点的兄弟结点为黑色,此时又分为几种情况:
- 3.2.1.若新插入节点为父节点的左孩子,则将父节点标为黑色,祖先节点标为红色,对祖先节点进行右旋。
- 3.2.2.若新插入节点为父节点的右孩子,则将父节点进行左旋,这样就又变成了3.2.1中的左孩子问题。
红黑树的删除
-
1.被删除的节点的两个孩子都为NIL
- 1.1.如果删除的节点为红色,则直接删除
- 1.2.如果删除的节点为黑色
- 1.2.1.如果删除节点的兄弟节点两个孩子结点都为NIL,则删除该节点,并将兄弟节点标为红色,且父节点标为黑色。
- 1.2.2.如果删除节点的兄弟节点有一个孩子结点为NIL,一个孩子结点不为NIL
- 1.2.2.1.当不为NIL的孩子节点为右孩子时,将该孩子节点标为黑色,兄弟节点标为和父节点相同的颜色,父节点标为黑色,在根据父节点进行一次左旋
- 1.2.2.2.当不为NIL的孩子节点为左孩子时,将该孩子节点标为黑色,兄弟节点标为红色,以兄弟节点进行一次右旋,转为右孩子的情况,将右孩子标为和父节点相同的颜色,父节点标为黑色,兄弟节点表为黑色,再以父节点进行左旋。
- 1.2.3.如果删除节点的兄弟节点两个孩子都不为NIL。
- 1.2.3.1.如果兄弟节点为黑色,则两个孩子节点一定为红色,此时,将兄弟节点的右孩子节点标为黑色,将兄弟节点标为和父节点相同的颜色,将父节点标为黑色,并将兄弟节点的左孩子节点放到父节点的右孩子节点上,以父节点进行左旋。
- 1.2.3.2.如果兄弟节点为红色,则两个孩子节点一定为黑色,此时,将兄弟节点标为黑色,兄弟节点的左孩子节点标为红色,将兄弟节点的左孩子放到父节点的右孩子节点上,已父节点进行左旋。
2.删除节点的两个孩子都不为NIL
按照二叉查找树删除节点的方法找到D的后继节点S,交换D和S的内容(颜色保持不变),被删除节点变为S,如果S有不为NIL的节点,那么继续用S的后继节点替换S,直到被删除节点的两个孩子都为NIL,问题转化为被删除节点D的两个孩子都为NIL的情况。3.删除节点有一个孩子节点为NIL
这个孩子节点一定是红色,此时,用这个孩子节点替换删除的节点。
树之间的比较
B树和B+树
- 1.B+树数据存储在叶子结点,B树数据存储在各结点上,B+树单一结点存储的元素更多,使得IO次数更少。
- 2.B+树查询的数据都在叶子结点,B树各结点都有可能。B+树更稳定。
- 3.B+树所有的叶子结点形成了一个有序链表,查询更快。