5分钟学会红黑树插入(inserting elements into a red black tree)

前言:本文解决的问题

  • 什么是红黑树
  • 什么时候使用红黑树
  • 红黑树插入元素时如何保持平衡

1 什么是红黑树

红黑树(Black red Tree) 是一棵自平衡树,每个节点都遵循以下四条:

  • 所有节点只能是红色或者黑丝
  • 根节点是黑色
  • 只存在相邻的红色节点(即红色节点不能有红色的父节点或者红色的孩子)
  • 任意从root到Nil节点,经过的路径中黑色节点的数目是一样的。

具体可以见下图
红黑树例子

2 什么时候用红黑树

2.1 为什么会提出红黑树

我们知道,一般在平衡二叉树(BST)作插入、删除、更新、查找的时间复杂度是O(log n),但是对于那种变形的BST(往一边偏的,变成线性的)时间复杂度就会变成O(n)。红黑树提供了为插入删除提供了最坏的时间保证2O(log n) ,因为它可以保持自平衡,总能把高度维持在 2log(n+1) (n为节点数目)。

2.1 什么时候用红黑树

相比AVL树而言,红黑树没有严格定义左右子树高度差值,并不严格意义的平衡。如果要涉及到很多插入、删除,用AVL的话会很多次旋转(rotation),此时红黑树是更好的选择。反之,查询多,更改少,即静态的话AVL是更好的选择。在查询效率上,由于AVL树严格平衡,AVL树会比红黑树略快,但时间复杂度是要给数量级上的。此外,相比较AVL树而言,红黑树需要额外的O(n)的空间来存储颜色。

在java集合框架中TreeSet和TreeMap是用红黑树实现的。


# 3 红黑树的插入 ## 3.1 插入情况分类 放方便后续说明,假设要插入的节点为Z,插入后Z的父节点为,Z.parent;Z父节点的兄弟为Z.uncle
* Case 1插入后Z本身就是根元素 ![根元素](https://images2018.cnblogs.com/blog/1477033/201809/1477033-20180901194911304-1918982240.png) 如上图所示,插入后就只有这个一个元素,此时直接把该节点变为黑色即可。
* Case 2 插入后Z的父节点是黑色(Z.parent = black ) ![根节点是黑色](https://images2018.cnblogs.com/blog/1477033/201809/1477033-20180901200734636-503666096.png) 这种完全符合红黑树的特性,不需要做出更改
* Case 3 Z的父节点和叔叔节点都是红色(Z.uncle and parent = red/recolor) 这种违反了红黑树的第三代你特征,即不存在父子节点都是红色的,只需要把父节点和叔叔节点都变成黑色(Z.parent = black; Z.uncle = black),同时上面根节点颜色变成红色。
* Case 4 .Z的父节点是红色,叔叔节点是黑色,Z与父节点和祖父节之间是RL或者LR的情况。(即Z.parent = black and uncle = black(triangle) ->rotate.Z.parent) 和第三种一样违反了父子节点都是红色的特性。此时需要作的是把RL或者LR旋转变成LL或者RR情况的,具体做法就说旋转Z.parent.
* Case 5 Z的父节点红色,叔叔节点是黑色的,Z与父节点、祖父节点在一条线上,即LL和RR的情况。(Z.uncle = black(line)->rotate.Z.grandparent &&recolor) 旋转Z的祖父节点,并重新着色,使满足红黑树特性。 ![case 5](https://images2018.cnblogs.com/blog/1477033/201809/1477033-20180901201038325-1676518169.png)
##3.2 实际举例(针对case3、case4和case5分别举例)
下图中10是要加入的节点,初始树如下 ![初始树](https://images2018.cnblogs.com/blog/1477033/201809/1477033-20180901201011041-1072835040.png)
### case 3,父亲和叔叔节点都是红色的 把10加在末尾,涂红色 ![case 3-1](https://images2018.cnblogs.com/blog/1477033/201809/1477033-20180901201957680-70425620.png) 把Z.parent 变成黑色,Z.uncle变成黑色,为维持从上往下的路径中黑色节点数量不变,需要把Z.grandparent=red
![case 3-2](https://images2018.cnblogs.com/blog/1477033/201809/1477033-20180901202058131-1059783593.png)
### case 3,叔叔节点黑色,而且是三角形的,如图 ![case 4-1](https://images2018.cnblogs.com/blog/1477033/201809/1477033-20180901201659006-953306750.png)
把Z.parent旋转 ![case-4-2](https://images2018.cnblogs.com/blog/1477033/201809/1477033-20180901201850592-1995238849.png)
结果如下 ![case4-3](https://images2018.cnblogs.com/blog/1477033/201809/1477033-20180901201909652-1358636274.png)
### case 5,叔叔节点黑色,而且是线性的,如图 ![case 5-1](https://images2018.cnblogs.com/blog/1477033/201809/1477033-20180901202219328-1039182969.png)
旋转Z的祖父节点,rotate the Z.grandparent,如图: ![case 5-2](https://images2018.cnblogs.com/blog/1477033/201809/1477033-20180901202338463-43438636.png)
把旋转后的重新着色

case 5-3

4总结

红黑树的插入元素,总的来说分两部,先旋转,再着色。旋转把RL和LR型变成RR或者LL型,然后再旋转上一级元素;着色要满足红黑树的特性

参考文献

https://en.wikipedia.org/wiki/Red–black_tree

posted @ 2018-09-01 20:38  想飞_毛毛虫  阅读(2778)  评论(0编辑  收藏  举报