算法:红黑树
红黑树介绍
红黑树(英语:Red–black tree)是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。它是在1972年由鲁道夫·贝尔发明的,他称之为"对称二叉B树",它现代的名字是在Leo J. Guibas和Robert Sedgewick于1978年写的一篇论文中获得的。
红黑树本质上是一种二叉查找树,但它在二叉查找树的基础上额外添加了一个标记(颜色),同时具有一定的规则。这些规则使红黑树保证了一种平衡,插入、删除、查找的最坏时间复杂度都为 O(logn)。它的统计性能要好于平衡二叉树(AVL树),因此,红黑树在很多地方都有应用。比如在 Java 集合框架中,很多部分(HashMap, TreeMap, TreeSet 等)都有红黑树的应用,这些集合均提供了很好的性能。
由于 TreeMap 就是由红黑树实现的,因此本文将使用 TreeMap 的相关操作的代码进行分析、论证。
二叉查找树问题
二叉排序树的性能取决于二叉树的层数:
- 最好的情况是 O(logn),存在于完全二叉排序树情况下,其访问性能近似于折半查找;
- 最差时候会是 O(n),比如插入的元素是有序的,生成的二叉排序树就是一个链表,这种情况下,需要遍历全部元素才行.
如上图所示,同一组元素构成的形态不同,性能不同的二种树形结构。所以呢,我们引入红黑树是要解决这种树形不平衡的问题。
红黑树的性质
红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色或黑色。在二叉查找树的性质之上,红黑树还有如下的一些性质:
1.节点是或者黑色,但是根节点一定是黑色。
2.所有叶子节点都是黑色(叶子是NIL节点)
3.每个红色节点必须有两个黑色子节点,红色节点不连续,但是黑色节点是可以连续的。
4.从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。对于任意结点而言,其到叶结点树尾端NIL指针的每条路径都包含相同数目的黑结点。
树的旋转知识
当我们在对红黑树进行插入和删除等操作时,对树做了修改,那么可能会违背红黑树的性质。
为了继续保持红黑树的性质,我们可以通过对结点进行重新着色,以及对树进行相关的旋转操作,即修改树中某些结点的颜色及指针结构,来达到对红黑树进行插入或删除结点等操作后,继续保持它的性质或平衡。
树的旋转,分为左旋和右旋,以下借助图来做形象的解释和介绍:
左旋
从右往左看是左旋,首先我们要左旋X,以X-Y为轴左转,X到达原先a的位置,那谁来接替X的位置呢,当然是Y,也就是X本来就小于Y,Y到达X的位置后,X必然要当Y的左节点。那此时Y节点的左边指向X的话,那么原先指向的b应该去哪里呢,b大于X,小于Y,固然只能挂靠在X的右边。C节点本来就大于Y,故仍然在Y的右边。同理A节点本来就小于X,故仍然在X的左边。
TreeMap的实现代码
private void rotateLeft(Entry<K,V> p) { if (p != null) { Entry<K,V> r = p.right; //r = 图 Y p.right = r.left; // if (r.left != null) r.left.parent = p; r.parent = p.parent; if (p.parent == null) root = r; else if (p.parent.left == p) p.parent.left = r; else p.parent.right = r; r.left = p; p.parent = r; } }
右旋
右旋的思路同左旋,此处不在赘述。
TreeMap的实现代码
private void rotateRight(Entry<K,V> p) { if (p != null) { Entry<K,V> l = p.left; p.left = l.right; if (l.right != null) l.right.parent = p; l.parent = p.parent; if (p.parent == null) root = l; else if (p.parent.right == p) p.parent.right = l; else p.parent.left = l; l.right = p; p.parent = l; } }
原文地址:https://www.cnblogs.com/MrSaver/p/9876380.html