二叉排序树、平衡二叉树以及红黑树

现实生活中,有很多找东西的例子,比如在学校找某个人,在驿站找快递,在信息登记表上查找某个人的信息,那么在计算机科学中,具体有哪些可以加快查找的算法?下面我们就来看看其中的动态查找算法,动态查找的意思是当你查找某个键值的信息,若存在则输出,否则将插入该键值为后续进行查找。

二叉排序树

首先我们来看看二叉排序树,二叉排序树有点类似于二分查找的思路,但是它用树的形式来表示查找的方向。
定义:
(1)一个二叉排序树要么是一个空树,要么是具有下面性质的二叉树;
(2)若它的左子树不空,则左子树的所有结点都小于它的根节点;
(3)若它的右子树不空,则右子树的所有结点都大于它的根节点;
(4)它的左、右子树也分别是一个二叉排序树。
例子:
这里写图片描述
根据上图再去看看是否满足上面所说的性质,我们发现这是一颗二叉排序树,对它进行中序遍历可以得到有序序列。
查找算法:
二叉排序树的查找算法是非常简单的,类似于二分查找,二叉排序树的查找从根节点出发,比较根节点键值与待查的值的大小,如果待查值较大,就往右边走,如果待查值较小,就往左边走,如果相等就找到了。以此类推,直到叶节点,如果还没找到,将作为某叶节点的孩子。
比如对于上图,要查找关键值5,从7开始找,比7小,往左走来到2,比2大往右走就找到了关键字5.
二叉排序树的构造:
先构造空树,然后查找一系列的关键字就会生成二叉排序树了。因为当关键字查找不到的时候,就会插入到树里面,因此就构造出了二叉排序树了。
二叉排序树的删除:
只要保证二叉排序树的性质,删除某一个节点将不会对树造成影响。删除某个结点主要有以下三种情况:
(1)该节点是叶节点,直接删除;
(2)该节点只有一个孩子,则让它的孩子接替它的位置就可以了。
(3)该节点有两个孩子,这时不能随便删除,应该选择该节点(P)的左孩子的最右后代(S)接替它的位置,同时S的左孩子作为S节点的父节点的右孩子,S的右孩子还是S的右孩子。
查找性能分析:
通过查找算法我们可以知道,查找时间跟该节点到根节点的路径长度有关,那么如果这个树比较类似于完全二叉树,那么树高为lgn,则查找时间也为lgn,可是如果二叉排序树是一个直直的斜树(每个节点只有左孩子或者只有右孩子),那么查找时间就和线性查找时间一样,大概为n/2。因此,我们要想办法让这个树比较类似于完全二叉树,使得左边的节点个数与右边的节点个数较为平衡,来保证较好的查找性能,下面给出两种平衡二叉树的基本定义。

平衡二叉树(AVL树)

定义:
(1)它或者是一颗空树或者具有以下性质的二叉树;
(2)它的左子树和右子树的高度差绝对值不超过1;
(3)它的左子树和右子树也是一颗平衡二叉树;
根据上面的性质,定义二叉树上结点的平衡因子为它的左子树高度减去右子树高度,因此平衡因子的值只能为0,1,-1;
下图就是一个简单的平衡二叉树:
这里写图片描述
其中树节点的值为平衡因子的值,即节点左孩子高度减去右节点的高度值。
查找性能分析:
显然查找的时间跟树的深度有关,那么对于一个含n个关键字的平衡树的最大深度是多少?当然是平衡树达到平衡的临界值的时候,在临界值这个状态,添加一个结点可能是平衡树失衡,减少一个结点也可能使平衡树失衡。于是,这个问题就转化为深度为h的平衡二叉树最少结点是多少的问题。显然当树规模比较少时,我们可以得出:
这里写图片描述
当h>=4时,满足以下式子:

N(h)=N(h-1)+N(h-2)+1

其中N(h)表示高度为h的平衡树的节点个数。
不妨设左子树的高度大于右子树的高度,则有以下不等式:

N(h)=N(h-1)+N(h-2)+1>2*N(h-2)+1>2*N(h-2)>2*2*N(h-4)>…>2^(h/2)

分别对上面的不等式取对数(注意,底数是2)得:

lgN(h)>lg(2^(h/2))=h/2

因此树高h<2lgN。
综上,一颗有n个节点的AVL树高度为O(lgn),即最坏情况下查找时间为O(lgn)。这是很不错的结果了。
平衡二叉树的插入:
然而,好结果是需要付出代价的。
代价就是你在插入新节点的时候必须时刻保持树的每一个节点的平衡;失衡是由下面的节点(第一个不平衡的节点)引起的,因此只要下面的节点平衡了,整棵树就平衡了。树的插入有四种,其中两两是关于左右对称的,因此只要掌握两种就知道另外两种怎么做。为了平衡二叉树,需要对树节点进行旋转对换。对换的原则就是保证对换以后能够满足中序遍历得到有序序列的条件。
(1)LL型:
这里写图片描述
在上图中,我们插入结点1,导致了结点5的平衡因子变成2,就失去了平衡。为了使整棵树平衡,只需要调整以5为根节点的子树。
这种情况是在5的左孩子3插入左孩子导致的,因此可以以3为旋转点,顺时针旋转得到右边的树。
(2)LR型:
这里写图片描述
在7的左孩子4的右孩子6插入结点5,导致7失衡。这时需要先左旋,即将7以4为旋转中心左旋,然后6再右旋,得到右图的平衡树。
(3)另外两种都是在右子树插入结点,可以根据前面两种情况知道怎么旋转使树平衡,就不细说了。

红黑树

红黑树顾名思义,就是由红色结点和黑色结点组成的一种“平衡”二叉树。
定义:
(1)每个节点是红色或者黑色的;
(2)根节点是黑色的;
(3)叶节点是黑色的;
(4)如果一个节点是红色的,它的两个子节点是黑色的;
(5)对于每个节点,从该节点到叶节点的简单路径上,均包含相同个数的黑色结点,即黑高(某节点到叶节点的简单路径的黑色节点个数)相同。
下图就是一颗红黑树:
这里写图片描述
查找性能:
设bh(x)是x节点的黑高,首先需要证明x节点至少含有2^bh(x)-1个内部节点。
用归纳法可以证明:
当n=0即x为叶节点时,2^0-1=0,满足条件。
当n=x-1时,假设至少有2^(bh(x)-1)个内部节点;
当n=x时,以x为根的节点至少包含(2^(bh(x)-1)-1)+(2^(bh(x)-1)-1)+1=2^bh(x)-1;
证毕。
根据性质4,在x节点到叶节点的简单路径上,至少有一般的节点是黑色的,所以bh(x)>=h/2;h为树的高度。
故上式变为:

n>=2^(h/2)-1

其中n表示以x为根节点的数的节点总和。
分别取对数得到:

h<=2(lgn+1)

因此,关键字的查找在红黑树上总是能够以O(lgn)的时间复杂度完成。
红黑树的插入和删除:
与AVL树相同,红黑树在插入新节点的过程中,也需要用旋转以及修改节点的颜色来满足红黑树的性质。具体的插入和删除也是分情况讨论的,限于本人的水平以及篇幅,不再细说。如果你感兴趣,可以参考算法导论第三版第十三章。已经证明,红黑树的插入和删除操作也只需要在lgn的时间复杂度内完成。
红黑树和AVL树的区别: (1)查找:AVL树会比红黑树快一点点,因为AVL树会让每一个结点达到严格的平衡。因此AVL树高会低于红黑树树高; (2)插入和删除:AVL树慢于红黑树,因为AVL树需要保证严格的平衡,因此需要花费更多的时间来保证平衡。 (3)空间:AVL树需要至少两个位来保存平衡因子的值,而红黑树只需要1位保存颜色值。