1. 二叉排序树(binary search tree,BST)
二叉排序树(又名二叉查找树)或者是一棵空树;或者是具有以下性质的二叉树:
1)若它的左子树不为空,则左子树上所有结点的值均小于它根节点的值
2)若它的右子树不为空,则右子树上所有结点的值均大于它根节点的值
3)它的左右子树也分别为二叉排序树
例子:
二叉排序树的优点
利用了二分查找的思想,当查找或者插入数据时,都是通过一层层比较大小,找到查找值所在位置或者适合新节点插入的位置。查找所需的次数等于二叉查找树的高度。
在最好的情况下(二叉树平衡),查找的时间复杂度是o(logn),但是最坏的情况下(线性二叉树),查找的时间复杂度o(n).
二叉排序树的缺点
同样的关键字集合有可能导致不同的树结构索引,构建的树结构索引的搜索性能在最糟的情况下,有可能是线性的。
二叉搜索树的构建和遍历
二叉排序树插入相同值的处理
二叉树是一种动态查找表。特点是,树的结构不是一次生成的,而是在查找过程中,当树中不存在关键字等于给定值的结点时再进行插入。新插入的结点一定是一个新添加的叶子结点,并且是查找不成功时查找路径上访问的最后一个结点的左孩子或右孩子结点。
所以如果树中已经存在和待插入结点相同值的结点,那么这个结点会被去掉,插入的动作不会成功。
2.平衡二叉树(balanced binary search tree)(AVL树)
平衡二叉树的目的是为了减少二叉查找树层次,提高查找速度。
平衡二叉树或为空树,或为如下性质的二叉排序树:
(1)左右子树深度之差的绝对值不超过1;
(2)左右子树仍然为平衡二叉树.
平衡因子BF(Balance Factor)
若将二叉树上结点的平衡因子BF(Balance Factor)定义为该结点的左子树的深度减去它的右子树的深度,则平衡二叉树上左右结点的平衡因子只能是-1、0和1.只要二叉树上有一个结点的BF的绝对值大于1,这个二叉树就是不平衡的。
如何进行自平衡
可分为四种:
- LL(左左):由于在* a的左子树根节点的左子树上插入结点,* a的BF由1增至2,致使以* a为根节点的子树失去平衡。需要一次向右的顺时针旋转操作
示例:在子树T0上添加新节点后,根节点g的左右子树失衡,g->T0 比 g->T3 深度多了2。需对g节点执行一次右旋转,具体步骤为:
g.left = p.right; //g的左孩子指向p的右孩子
p.right = g; //g变成p的右孩子
root = p; //p作为新的根
- LR(左右):由于在* a的左子树根节点的右子树上插入结点,* a的BF由1增至2,致使以* a为根节点的子树失去平衡。需要两次旋转(先左旋后右旋)操作
示例:在子树T2上添加新节点后,根节点g的左右子树失衡,g->T2 比 g->T3 深度多了2。这时先对p节点执行一次左旋转(虽然以p为根的树平衡并未打破,但这是必要的准备工作),经过一次左旋后,g的左孩子的左子树“过重”失衡了,可以归于“左左”的情形。(假设新节点插入位置是子树T1,左旋后仍是“左左”的情况)再对g节点执行一次右旋转即可重新平衡:具体步骤为:
//左旋
p.right = n.left; //p的左孩子指向n的右孩子
n.left = p; //p变成n的左孩子
root = n; //n作为子树新的根
//右旋
g.left = p.right; //g的左孩子指向p的右孩子
p.right = g; //g变成p的右孩子
root = p; //p作为新的根
RR(右右):左左的镜像问题。只需对g执行一次左旋(逆时针旋转)
RL(右左):左右的镜像问题。先右旋后左旋。
3.适度平衡二叉树:红黑树(Red Black Tree)
红黑树是一种自平衡的二叉查找树,除了符合二叉查找树的特性外,还有以下附加特性:
红黑树基本性质:
1)每个节点或者是黑色,或者是红色
2)根节点是黑色
3)每个叶子结点(NIL,这里的叶子结点不是传统的叶子结点,是指为空的叶子结点)是黑色。
4)如果一个结点是红色的,则它的子结点必须是黑色的
5)从一个结点到该结点的子孙结点的所有路径上包含相同数目的黑结点。
红黑树是一个“适度平衡”的二叉搜索树,而非如AVL一般“严格”的平衡。红黑树中最长路径的长度必然“不大于”最短路径的2倍,所以不妨设Max者为H,Min者为h。则有:H<=2h。而从搜索的角度考虑,其复杂度为O(h)的,最长支路的搜索时间为O(H)<=O(2h)。所以从渐进复杂度的角度考虑二者是同一数量级的(同阶无穷大)。因此从这个角度讲红黑树也算是“平衡”的。
插入或者删除结点时红黑树的某些规则可能会被打破,所以需要做出一些调整来维持规则
以插入结点为例
不影响红黑树的规则的情况,插入值为14的新节点:
破坏红黑树的规则的情况,插入值为21的新节点
因为叶子节点必须要是黑色,所以插入的21必须是红色,但是按照图中的情况,由于父节点22是红色节点,子节点21也为红色的情况打破了红黑树的规则4(每个红色节点的两个子节点都是黑色),必须进行调整,使之重新符合红黑树的规则。
红黑树调整的方式:变色和旋转
变色
为了重新符合红黑树的规则,尝试把红色节点变为黑色,或者把黑色节点变为红色。
以插入节点21为例,因为节点21和节点22连续出现了红色,不符合规则4,所以把节点22从红色变成黑色:(图为整棵树的一个部分)
但是凭空多出的黑色节点打破了规则5,即从一个结点到该结点的子孙结点的所有路径上包含相同数目的黑结点。所以发生连锁反应,需要继续把节点25从黑色变成红色。
但是这时点25和节点27又形成了两个连续的红色节点,需要继续把节点27从红色变成黑色:
最后得到
把节点8和节点17进行变色,由红色节点变成黑色节点。这样以来就形成了新的红黑树
旋转
平衡二叉树指针结构的修改方式:左旋和右旋
左旋转:逆时针旋转红黑树的两个节点,使得父节点被自己的右孩子取代,而自己成为自己的左孩子。
右旋转:顺时针旋转红黑树的两个节点,使得父节点被自己的左孩子取代,而自己成为自己的右孩子
5. 为什么说红黑树、B-树、B+树都是自平衡二叉树
因为当插入、删除操作破坏了红黑树、B-树或者B+树的平衡性时,它们都会通过对应的操作来恢复平衡。
比如红黑树采用变色和旋转;B-树、B+树也会发生连锁改变来维持平衡,具体操作见Mysql常见面试问题整理(二):索引
参考
【1】自平衡二叉树(Self-balancing binary search tree)
【】数据结构之二叉排序树的建立
【】二叉排序树插入相同值的处理
【2】彻底搞懂平衡二叉树(AVL)建树过程(左旋、右旋)
【3】【红黑树】一定是平衡二叉树吗?下面这个树呢?
【4】漫画:什么是红黑树?
【】维基百科