红黑树总结
Posted 程序猿与喵星草的日常
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了红黑树总结相关的知识,希望对你有一定的参考价值。
红黑树是一种很经典的数据结构,它可以在O(log n)时间内做查找,插入和删除。所以倍受关注。但是一直以来很多Java程序员对他都不是很重视,直到在JDK 1.8中,HashMap会将其链表转换成红黑树,此后,很多人就开始重新学习红黑树的有关知识。
作者在学习红黑树时,查阅了很多资料都没有找到解释的特别清楚的,于是自己总结了这一篇文章,总字数近7k,而且绘制了很多图,希望可以让大家更容易理解。
1. 定义
红黑树是Avl树的一个变种,它也是在二叉查找树的基础上添加平衡条件,只是它对平衡条件的描述不像AVl树那样直接,而是转化成对节点颜色规则的描述。
-
对于任意节点,要么是红色,要么是黑色; -
根节点是黑色的; -
如果一个节点是红色的,那么它的子节点必须是黑色的(即不能有两个连续的红色节点); -
任意节点到其下面各个空结点(后面称为nil节点,并约定其颜色为黑色)的路径上都包含相同数目的黑色节点(称为黑高);
2. 分析实现
2.1. 插入
1. 如果parent为红色,uncle为黑色
2. 如果parent为红色,uncle为红色
以情况3为例:
先对X与其子节点进行颜色翻转
2.2. 删除
1.parent为红色,brother为黑色
由于current是树叶,那么可以断定brother下面不会再有黑色的后代节点,至多只能有红色的儿子节点,否则parent在删除前将违反规则4。
2.parent为黑色,brother为红色
同样由于current是树叶,可以断定brother的两个黑色的儿子节点下面至多只能有一层红色子节点,下面根据brother左儿子的子节点情况(右儿子的子节点没有影响,因此忽略)来分情形讨论。
3.parent为黑色,brother为黑色
还是由于current是树叶,可以断定brother下面至多只能有一层红色的儿子节点,否则parent在删除前就违反了规则4。
3. java实现
Set
和
MultiTreeMap
3.1. Set
public class RBTreeSet<E extends Comparable<? super E>> extends BinarySearchTreeSet<E> {
private RBNode<E> header;
private RBNode<E> nil;
public RBTreeSet() {
nil = new RBNode<>(null);
nil.left = nil;
nil.right = nil;
header = new RBNode<>(null, nil, nil);
}
@Override
protected Node<E> getRoot() {
return header.right;
}
@Override
protected boolean isEmptyNode(Node<E> node) {
return nil == node;
}
@Override
public void clear() {
header.right = nil;
size = 0;
}
@Override
public boolean add(E e) {
RBNode<E> current = header;
RBNode<E> parent = header;
//先将nil的值设为e
nil.element = e;
//然后从header开始自上而下寻找值为e的节点a
while(compare(e, current) != 0){
parent = current;
if(compare(e, current) < 0){
current = getLeft(current);
}else{
current = getRight(current);
}
//如果左右子节点都为红色,则进行颜色翻转,避免插入时出现父亲的兄弟节点为红色的情况
if(getLeft(current).red && getRight(current).red){
current = handleReorient(current);
}
}
//如果发现了值相同的重复节点,直接覆盖
if(current != nil){
current.element = e;
return true;
}
//新建一个数据节点代替nil,并将其左右子树指向nil
current = new RBNode<>(e, nil, nil);
size++;
//当while结束时,必然可以明确待插入节点的parent节点,这里使parent节点链接到新节点
current.parent = parent;
if(compare(e, parent) < 0){
parent.left = current;
}else{
parent.right = current;
}
//将新数据节点设成红色,如果父亲节点为红色则需要旋转调整
handleReorient(current);
return true;
}
private RBNode<E> getLeft(Node<E> node){
return (RBNode<E>)node.left;
}
private RBNode<E> getRight(Node<E> node){
return (RBNode<E>)node.right;
}
private int compare(E e, Node<E> node) {
if(node == header){
return 1;
}else{
return e.compareTo(node.element);
}
}
private RBNode<E> handleReorient(RBNode<E> current) {
getLeft(current).red = false;
getRight(current).red = false;
current.red = true;
RBNode<E> subRoot = current;
//翻转之后发现parent也是红色,进行换色和旋转
RBNode<E> parent = current.parent;
if(parent.red){
RBNode<E> grand = parent.parent;
grand.red = true;
//旋转parent, 向外旋转到同一侧
if(compare(current.element, grand) != compare(current.element, parent)) {
if(compare(current.element, parent) > 0){
rotateLeft(parent);
}else{
rotateRight(parent);
}
}
//旋转grand
if(compare(current.element, grand) < 0){
subRoot = getLeft(grand);
subRoot.red = false;
rotateRight(grand);
}else{
subRoot = getRight(grand);
subRoot.red = false;
rotateLeft(grand);
}
}
//直接将根节点置为黑色
getRight(header).red = false;
return subRoot;
}
private void rotateRight(RBNode<E> node) {
RBNode<E> parent = node.parent;
RBNode<E> left = getLeft(node);
RBNode<E> leftRight = getRight(left);
left.right = node;
node.parent = left;
node.left = leftRight;
leftRight.parent = node;
left.parent = parent;
if(parent.right == node){
parent.right = left;
}else{
parent.left = left;
}
}
private void rotateLeft(RBNode<E> node) {
RBNode<E> parent = node.parent;
RBNode<E> right = getRight(node);
RBNode<E> rightLeft = getLeft(right);
right.left = node;
node.parent = right;
node.right = rightLeft;
rightLeft.parent = node;
right.parent = parent;
if(parent.right == node){
parent.right = right;
}else{
parent.left = right;
}
}
@Override
public boolean remove(Object o) {
RBNode<E> current = header;
RBNode<E> parent = header;
@SuppressWarnings("unchecked")
E e = (E)o;
nil.element = e;
while(compare(e, current) != 0){
parent = current;
if(compare(e, current) < 0){
current = getLeft(current);
}else{
current = getRight(current);
}
}
if(current == nil){ //没有找到值为e的数据节点
return true;
}
size--;
RBNode<E> node = current;
if(current.right != nil){ //替换右子树最小节点
parent = current;
current = getRight(current);
while(current.left != nil){
parent = current;
current = getLeft(current);
}
node.element = current.element;
//右侧最小节点不是叶子,则继续向下遍历一层,这时可以断定树叶是红色
if(current.right != nil){
parent = current;
current = getRight(current);
parent.element = current.element;
parent.right = nil;
return true;
}
}else if(current.left != nil){ //替换左子树最大节点
parent = current;
current = getLeft(node);
while(current.right != nil){
parent = current;
current = getRight(current);
}
node.element = current.element;
//左侧最大节点不是叶子,则继续向下遍历一层,这时可以断定树叶是红色
if(current.left != nil){
parent = current;
current = getLeft(current);
parent.element = current.element;
parent.left = nil;
return true;
}
}
//先调整再删除,因为后面还需要依赖current与parent的位置关系判断
if(!current.red){
fixRemove(current);
}
//删除树叶leaf
if(current == parent.left){
parent.left = nil;
}else{
parent.right = nil;
}
return true;
}
private void fixRemove(RBNode<E> current){
RBNode<E> parent = current.parent;
if(parent == header){
return;
}
if(current == parent.left){
RBNode<E> brother = getRight(parent);
if(parent.red){ // 1.parent为红色
if(getLeft(brother).red){
parent.red = false;
rotateRight(brother);
}
}else if(brother.red){ // 2.brother为红色
if(!getLeft(brother.left).red && !getRight(brother.left).red){
brother.red = false;
getLeft(brother).red = true;
}else if(getRight(brother.left).red){
getRight(brother.left).red = false;
rotateRight(brother);
}else{
getLeft(brother.left).red = false;
rotateRight(getLeft(brother));
rotateRight(brother);
}
}else{ // 3. parent和brother都为黑色
if(!getLeft(brother).red && !getRight(brother).red){
brother.red = true;
fixRemove(parent);
return;
}else if(getRight(brother).red){
getRight(brother).red = false;
}else{
getLeft(brother).red = false;
rotateRight(brother);
}
}
//最后一步的调整都是parent左旋
rotateLeft(parent);
}else{ // 对称情形
RBNode<E> brother = getLeft(parent);
if(parent.red){
if(getRight(brother).red){
parent.red = false;
rotateLeft(brother);
}
}else if(brother.red){
if(!getLeft(brother.right).red && !getRight(brother.right).red){
brother.red = false;
getRight(brother).red = true;
}else if(getLeft(brother.right).red){
getLeft(brother.right).red = false;
rotateLeft(brother);
}else{
getRight(brother.right).red = false;
rotateLeft(getRight(brother));
rotateLeft(brother);
}
}else{
if(!getLeft(brother).red && !getRight(brother).red){
brother.red = true;
fixRemove(parent);
return;
}else if(getLeft(brother).red){
getLeft(brother).red = false;
}else{
getRight(brother).red = false;
rotateLeft(brother);
}
}
rotateRight(parent);
}
}
static class RBNode<E> extends Node<E> {
RBNode<E> parent;
boolean red;
RBNode(E e) {
super(e);
}
RBNode(E e, RBNode<E> left, RBNode<E> right) {
super(e);
this.left = left;
this.right = right;
}
@Override
public String toString() {
return red ? element.toString() + "(red)" : element.toString();
}
}
}
3.2. MultiTreeMap
public class MultiRBTreeMap<K extends Comparable<? super K>, V> extends MultiBinarySearchTreeMap<K, V> {
public MultiRBTreeMap() {
}
public MultiRBTreeMap(boolean deduplication, boolean asc){
super(deduplication, asc);
}
@Override
protected void init() {
nil = new RBNode<K, V>(null, null, false, null, null);
nil.left = nil;
nil.right = nil;
header = new RBNode<K, V>(null, null, false, nil, nil);
header.next = nil;
nil.prev = header;
}
public V put(K key, V value){
nil.key = key;
RBNode<K, V> current = (RBNode<K, V>)header;
RBNode<K, V> parent = (RBNode<K, V>)header;
while(compare(key, current) != 0){
parent = current;
if(compare(key, current) < 0){
current = getLeft(current);
}else{
current = getRight(current);
}
if(getLeft(current).isRed && getRight(current).isRed){
current = handleReorient(current);
}
}
if(current != nil){
if(deduplication){
V old = current.value;
current.key = key;
current.value = value;
return old;
}else{
while((current = getNext(current)).isRepeat);
V old = current.prev.value;
linkIn(new RBNode<>(key, value, true, nil, nil), current, false);
return old;
}
}
current = new RBNode<>(key, value, false, nil, nil);
current.parent = parent;
if(compare(key, parent) < 0){
parent.left = current;
linkIn(current, parent, false);
}else{
parent.right = current;
while((parent = getNext(parent)).isRepeat);
linkIn(current, parent, false);
}
//将新数据节点设成红色,如果父亲节点为红色则需要旋转调整
handleReorient(current);
return null;
}
private RBNode<K, V> handleReorient(RBNode<K, V> current) {
getLeft(current).isRed = false;
getRight(current).isRed = false;
current.isRed = true;
RBNode<K, V> subRoot = current;
RBNode<K, V> parent = getParent(current);
if(parent.isRed){
RBNode<K, V> grand = getParent(parent);
grand.isRed = true;
//旋转parent, 向外旋转到同一侧
if(compare(current.getKey(), grand) != compare(current.getKey(), parent)) {
if(compare(current.getKey(), parent) > 0){
rotateLeft(parent);
}else{
rotateRight(parent);
}
}
//旋转grand
if(compare(current.getKey(), grand) < 0){
subRoot = getLeft(grand);
subRoot.isRed = false;
rotateRight(grand);
}else{
subRoot = getRight(grand);
subRoot.isRed = false;
rotateLeft(grand);
}
}
//直接将根节点置为黑色
getRight(header).isRed = false;
return subRoot;
}
private void rotateRight(Node<K, V> node) {
Node<K, V> parent = node.parent;
Node<K, V> left = node.left;
Node<K, V> leftRight = left.right;
left.right = node;
node.parent = left;
node.left = leftRight;
leftRight.parent = node;
left.parent = parent;
if(parent.right == node){
parent.right = left;
}else{
parent.left = left;
}
}
private void rotateLeft(Node<K, V> node) {
Node<K, V> parent = node.parent;
Node<K, V> right = node.right;
Node<K, V> rightLeft = right.left;
right.left = node;
node.parent = right;
node.right = rightLeft;
rightLeft.parent = node;
right.parent = parent;
if(parent.right == node){
parent.right = right;
}else{
parent.left = right;
}
}
private int compare(K key, Entry<K, V> node) {
if(node == header){
return 1;
}else{
return key.compareTo(node.getKey());
}
}
private RBNode<K, V> getParent(Node<K, V> node){
return (RBNode<K, V>)node.parent;
}
private RBNode<K, V> getNext(Node<K, V> node){
return (RBNode<K, V>)node.next;
}
private RBNode<K, V> getLeft(Node<K, V> node){
return (RBNode<K, V>)node.left;
}
private RBNode<K, V> getRight(Node<K, V> node){
return (RBNode<K, V>)node.right;
}
@Override
protected void remove(Node<K, V> node){
RBNode<K, V> rbnode = (RBNode<K, V>)node;
RBNode<K, V> current = rbnode;
RBNode<K, V> parent = getParent(current);
if(current.right != nil){
current = getRight(current);
while(current.left != nil){
parent = current;
current = getLeft(current);
}
locationExchange(rbnode, current);
if(rbnode.right != nil){//node.right is red
parent = rbnode;
rbnode = getRight(rbnode);
locationExchange(parent, rbnode);
rbnode.right = nil; //交换过位置
return;
}
}else if(current.left != nil){
current = getLeft(current);
while(current.right != nil){
parent = current;
current = getRight(current);
}
locationExchange(rbnode, current);
if(rbnode.left != nil){//node.left is red
parent = rbnode;
rbnode = getLeft(rbnode);
locationExchange(parent, rbnode);
rbnode.left = nil;
return;
}
}
if(!rbnode.isRed){
fixRemove(rbnode);
}else if(rbnode == parent.left){
parent.left = nil;
}else{
parent.right = nil;
}
}
//这里不能简单的交换节点的值,因为要保证链表和树中删除的是同一个节点实例即node
private void locationExchange(RBNode<K, V> node, RBNode<K, V> current){
RBNode<K, V> parent = getParent(node);
RBNode<K, V> left = getLeft(node);
RBNode<K, V> right = getRight(node);
boolean isRed = node.isRed;
replaceChild(current.parent, current, node);
node.left = current.left;
node.left.parent = node;
node.right = current.right;
node.right.parent = node;
node.isRed = current.isRed;
replaceChild(parent, node, current);
current.left = left;
left.parent = current;
current.right = right;
right.parent = current;
current.isRed = isRed;
}
private void fixRemove(RBNode<K, V> node){
RBNode<K, V> parent = getParent(node);
if(parent == header){
return;
}
if(node == parent.left){
parent.left = nil;
RBNode<K, V> brother = getRight(parent);
if(parent.isRed){ // 1.parent为红色
if(getLeft(brother).isRed){
parent.isRed = false;
rotateRight(brother);
}
}else if(brother.isRed){ // 2.brother为红色
if(!getLeft(brother.left).isRed && !getRight(brother.left).isRed){
brother.isRed = false;
getLeft(brother).isRed = true;
}else if(getRight(brother.left).isRed){
getRight(brother.left).isRed = false;
rotateRight(brother);
}else{
getLeft(brother.left).isRed = false;
rotateRight(brother.left);
rotateRight(brother);
}
}else{ // 3. parent和brother都为黑色
if(!getLeft(brother).isRed && !getRight(brother).isRed){
brother.isRed = true;
fixRemove(parent);
return;
}else if(getRight(brother).isRed){
getRight(brother).isRed = false;
}else{
getLeft(brother).isRed = false;
rotateRight(brother);
}
}
//最后一步的调整都是parent左旋
rotateLeft(parent);
}else{ // 对称情形
parent.right = nil;
RBNode<K, V> brother = getLeft(parent);
if(parent.isRed){
if(getRight(brother).isRed){
parent.isRed = false;
rotateLeft(brother);
}
}else if(brother.isRed){
if(!getLeft(brother.right).isRed && !getRight(brother.right).isRed){
brother.isRed = false;
getRight(brother).isRed = true;
}else if(getLeft(brother.right).isRed){
getLeft(brother.right).isRed = false;
rotateLeft(brother);
}else{
getRight(brother.right).isRed = false;
rotateLeft(brother.right);
rotateLeft(brother);
}
}else{
if(!getLeft(brother).isRed && !getRight(brother).isRed){
brother.isRed = true;
fixRemove(parent);
return;
}else if(getLeft(brother).isRed){
getLeft(brother).isRed = false;
}else{
getRight(brother).isRed = false;
rotateLeft(brother);
}
}
rotateRight(parent);
}
}
static class RBNode<K, V> extends Node<K, V> {
boolean isRed;
public RBNode(K key, V value) {
super(key, value);
}
RBNode(K key, V value, boolean isRepeat, Node<K, V> left, Node<K, V> right) {
super(key, value, isRepeat, left, right);
}
@Override
public String toString() {
String str = super.toString();
return isRed ? str + "(red)" : str;
}
}
}
3.3. MultiTreeSet
public class MultiRBTreeSet<E extends Comparable<? super E>> implements Set<E>{
private static final Object V = new Object();
private MultiRBTreeMap<E, Object> map;
public MultiRBTreeSet(){
map = new MultiRBTreeMap<>();
}
public int size() {
return map.size();
}
public boolean isEmpty() {
return map.isEmpty();
}
public boolean contains(Object o) {
return map.containsKey(o);
}
public Iterator<E> iterator() {
return map.keySet().iterator();
}
public Iterator<E> iterator(E from, boolean fromInclusive, E to, boolean toInclusive) {
return map.keySet(from, fromInclusive, to, toInclusive, false).iterator();
}
public boolean add(E e) {
map.put(e, V);
return true;
}
public boolean remove(Object o) {
map.removeList(o);
return true;
}
public boolean containsAll(Collection<?> c) {
return map.keySet().containsAll(c);
}
public void clear() {
map.clear();
}
public boolean addAll(Collection<? extends E> collection) {
for(E e : collection){
map.put(e, V);
}
return true;
}
public boolean removeAll(Collection<?> collection) {
for(Object o : collection){
map.removeList(o);
}
return true;
}
public boolean retainAll(Collection<?> c) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException();
}
public Object[] toArray() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException();
}
public <T> T[] toArray(T[] a) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException();
}
}
4. 红黑树的高度
MultiTreeMap
的原因。而在红黑树中,则可以将调整问题缩小在父节点为根的子树中, 这些问题都可以解决,代价只是稍微牺牲了一些平衡性。
-
《算法导论》 -
《数据结构与算法分析》
以上是关于红黑树总结的主要内容,如果未能解决你的问题,请参考以下文章
HashMap的工作原理以及代码实现,为什么要转换成红黑树?