一. 红黑树
红黑树是自平衡的二叉搜索树。搜索的时间复杂度是logN。插入,删除,旋转,染色的操作时间复杂度都是O(logN);每个节点只需要用一个bit来保存颜色(颜色仅为红黑两种)属性。
红黑树的每个节点有五个域(color,key,lchild,rchild,parent)。它会保存父节点的指针。
红黑树具有以下五个性质
①红黑树的节点必须是红色或者黑色。
②根节点必须是黑色
③叶节点是黑色的(这里的叶节点,不是传统意义上的树的页节点,而是说最下层的空节点,也就是传统意义上的叶节点的子节点。默认为黑色)
④红色节点必须有两个黑色节点的儿子
⑤从任一节点出发到其每个叶子节点的路径,黑色节点的数量是相等的。
手打太繁琐,关于红黑树下面的内容转自http://www.cnblogs.com/v-July-v/archive/2010/12/29/1983707.html
树的旋转知识
当我们在对红黑树进行插入和删除等操作时,对树做了修改,那么可能会违背红黑树的性质。
为了保持红黑树的性质,我们可以通过对树进行旋转,即修改树种某些结点的颜色及指针结构,以达到对红黑树进行
插入、删除结点等操作时,红黑树依然能保持它特有的性质(如上文所述的,五点性质)。
树的旋转,分为左旋和右旋,以下借助图来做形象的解释和介绍,这个旋转和平衡二叉树的旋转类似:
1.左旋
如上图所示:
当在某个结点pivot上,做左旋操作时,我们假设它的右孩子y不是NIL[T],pivot可以为树内任意右孩子而不是NIL[T]的结点。
左旋以pivot到y之间的链为“支轴”进行,它使y成为该孩子树新的根,而y的左孩子b则成为pivot的右孩子。
来看算法导论对此操作的算法实现(以x代替上述的pivot):
LEFT-ROTATE(T, x)
1 y ← right[x] ▹ Set y.
2 right[x] ← left[y] ▹ Turn y’s left subtree into x’s right subtree.
3 p[left[y]] ← x
4 p[y] ← p[x] ▹ Link x’s parent to y.
5 if p[x] = nil[T]
6 then root[T] ← y
7 else if x = left[p[x]]
8 then left[p[x]] ← y
9 else right[p[x]] ← y
10 left[y] ← x ▹ Put x on y’s left.
11 p[x] ← y
2.右旋
右旋与左旋差不多,再此不做详细介绍。
红黑树的插入操作(插入时把新节点作为红色节点):
情况1:插入的是根结点。
原树是空树,此情况只会违反性质2。
对策:直接把此结点涂为黑色。
情况2:插入的结点的父结点是黑色。
此不会违反性质2和性质4,红黑树没有被破坏。
对策:什么也不做。
情况3:当前结点的父结点是红色且祖父结点的另一个子结点(叔叔结点)是红色。
此时父结点的父结点一定存在,否则插入前就已不是红黑树。
与此同时,又分为父结点是祖父结点的左子还是右子,对于对称性,我们只要解开一个方向就可以了。
在此,我们只考虑父结点为祖父左子的情况。
同时,还可以分为当前结点是其父结点的左子还是右子,但是处理方式是一样的。我们将此归为同一类。
对策:将当前节点的父节点和叔叔节点涂黑,祖父结点涂红,把当前结点指向祖父节点,从新的当前节点重新开始算法。
针对情况3,变化前(图片来源:saturnman)[插入4节点]:
变化后:
情况4:当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的右子
对策:当前节点的父节点做为新的当前节点,以新当前节点为支点左旋。
如下图所示,变化前[插入7节点]:
变化后:
情况5:当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的左子
解法:父节点变为黑色,祖父节点变为红色,在祖父节点为支点右旋
如下图所示[插入2节点]
变化后:
红黑树的删除操作:
情况1:当前节点是红色
解法,直接把当前节点染成黑色,结束。
此时红黑树性质全部恢复。
情况2:当前节点是黑色且是根节点
解法:什么都不做,结束
情况3:当前节点是黑色,且兄弟节点为红色(此时父节点和兄弟节点的子节点分为黑)。
解法:把父节点染成红色,把兄弟结点染成黑色,之后重新进入算法(我们只讨论当前节点是其父节点左孩子时的情况)。
然后,针对父节点做一次左旋。此变换后原红黑树性质5不变,而把问题转化为兄弟节点为黑色的情况。
3.变化前:
3.变化后:
情况4:当前节点是黑色,且兄弟是黑色,且兄弟节点的两个子节点全为黑色。
解法:把当前节点和兄弟节点中抽取一重黑色追加到父节点上,把父节点当成新的当前节点,重新进入算法。(此变换后性质5不变)
4.变化前
4.变化后
情况5:当前节点颜色是黑色,兄弟节点是黑色,兄弟的左子是红色,右子是黑色。
解法:把兄弟结点染红,兄弟左子节点染黑,之后再在兄弟节点为支点解右旋,
之后重新进入算法。此是把当前的情况转化为情况6,而性质5得以保持。
5.变化前:
5.变化后:
情况6:当前节点颜色是黑色,它的兄弟节点是黑色,但是兄弟节点的右子是红色,兄弟节点左子的颜色任意。
解法:把兄弟节点染成当前节点父节点的颜色,把当前节点父节点染成黑色,兄弟节点右子染成黑色,
之后以当前节点的父节点为支点进行左旋,此时算法结束,红黑树所有性质调整正确。
6.变化前:
6.变化后:
二. B树
对于m阶B树
①每个节点之多有m棵子树(即之多含有m-1个关键字)
②若根节点不是终端节点,则至少有两棵子树
③除根节点以外的所有非叶节点至少有⌈m/2⌉棵子树。即至少包含⌈m/2⌉-1个关键字。
④所有非叶节点的结构为 n为节点个数,p为子树指针,k为关键字
n|p0|k1|p1|k2|p2…..|kn|pn
b树的所有节点的平衡因子都等于0,所有叶节点都处于同一层且不带任何信息。
B树的插入和删除,《数据结构》书里有,插入就是,关键字个数超过m-1个就分列,中间关键字上升。删除的话,就考虑够删不够删,不够删还得街关键词,找兄弟借或者父节点借。比较简单自行百度吧
三.B+树
对于m阶B+树
①每个分支最多有m棵子树。
②非叶根节点至少有两颗子树,其他每个分支节点至少有⌈m/2⌉子树。
③节点的子树个数与关键字个数相等。
④所有的叶节点包括含全部关键字及指向相应记录的指针,而且叶节点中将关键字按大小顺序排列,并且相邻叶节点按大小顺序连接起来。信息全部存在子节点上,分支节点仅为索引。
⑤所有分支节点仅包含它的多个子节点中关键字最大的值和指向子节点的指针。
B+树的插入和删除和B树类似,自行百度